From 60a008f635177acccaa9dacb4006491725c93702 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 10 Feb 2020 15:05:30 -0500
Subject: small cleanups to adding stacking views to contentfittingboxes (like
 time/pivot).  needs to have nativeWidth/Height set.

---
 .../views/collections/CollectionStackingView.tsx   | 35 +++++++++-------------
 1 file changed, 14 insertions(+), 21 deletions(-)

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index d772ace23..21c34d047 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -4,25 +4,25 @@ import { CursorProperty } from "csstype";
 import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import Switch from 'rc-switch';
-import { Doc, HeightSym, WidthSym, DataSym } from "../../../new_fields/Doc";
+import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
 import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
-import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from "../../../new_fields/Types";
-import { emptyFunction, Utils } from "../../../Utils";
+import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types";
+import { TraceMobx } from "../../../new_fields/util";
+import { Utils } from "../../../Utils";
 import { DragManager } from "../../util/DragManager";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
 import { EditableView } from "../EditableView";
 import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
+import { CollectionMasonryViewFieldRow } from "./CollectionMasonryViewFieldRow";
 import "./CollectionStackingView.scss";
 import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn";
 import { CollectionSubView } from "./CollectionSubView";
-import { ContextMenu } from "../ContextMenu";
-import { ContextMenuProps } from "../ContextMenuItem";
-import { CollectionMasonryViewFieldRow } from "./CollectionMasonryViewFieldRow";
-import { TraceMobx } from "../../../new_fields/util";
 import { CollectionViewType } from "./CollectionView";
 
 @observer
@@ -55,7 +55,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         this._docXfs.length = 0;
         return docs.map((d, i) => {
             const height = () => this.getDocHeight(d);
-            const width = () => this.widthScale * Math.min(d._nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns);
+            const width = () => Math.min(d._nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns);
             const dref = React.createRef<HTMLDivElement>();
             const dxf = () => this.getDocTransform(d, dref.current!);
             this._docXfs.push({ dxf: dxf, width: width, height: height });
@@ -376,16 +376,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         }
         return sections.map(section => this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1]));
     }
-    @computed get contentScale() {
-        const heightExtra = this.heightPercent > 1 ? this.heightPercent : 1;
-        return Math.min(this.props.Document[WidthSym]() / this.props.PanelWidth(), heightExtra * this.props.Document[HeightSym]() / this.props.PanelHeight());
-    }
-    @computed get widthScale() {
-        return this.heightPercent < 1 ? Math.max(1, this.contentScale) : 1;
-    }
-    @computed get heightPercent() {
-        return this.props.PanelHeight() / this.layoutDoc[HeightSym]();
-    }
+
+    @computed get scaling() { return !this.props.Document._nativeWidth ? 1 : this.props.PanelHeight() / NumCast(this.props.Document._nativeHeight); }
+
     render() {
         TraceMobx();
         const editableViewProps = {
@@ -399,9 +392,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                     ref={this.createRef}
                     style={{
                         overflowY: this.props.active() ? "auto" : "hidden",
-                        transform: `scale(${Math.min(1, this.heightPercent)})`,
-                        height: `${100 * Math.max(1, this.contentScale)}%`,
-                        width: `${100 * this.widthScale}%`,
+                        transform: `scale(${this.scaling}`,
+                        height: `${1 / this.scaling * 100}%`,
+                        width: `${1 / this.scaling * 100}%`,
                         transformOrigin: "top left",
                     }}
                     onScroll={action((e: React.UIEvent<HTMLDivElement>) => this._scroll = e.currentTarget.scrollTop)}
-- 
cgit v1.2.3-70-g09d2


From be02a5529f472507512a127cd8de5cde300eff88 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 11 Feb 2020 14:19:56 -0500
Subject: added ability to pass a Layout as a prop.  changed presentations to
 use layout props.  fixed creating a template for just an empty collection
 representing one field.

---
 src/client/util/DropConverter.ts                   |  7 +-
 src/client/views/DocComponent.tsx                  |  5 +-
 .../views/collections/CollectionStackingView.tsx   | 20 +++--
 .../CollectionFreeFormLayoutEngines.tsx            |  9 ++-
 .../views/nodes/ContentFittingDocumentView.tsx     |  6 +-
 src/client/views/nodes/DocumentContentsView.tsx    |  4 +-
 src/client/views/nodes/DocumentView.tsx            |  3 +-
 src/client/views/nodes/FieldView.tsx               |  1 +
 src/client/views/nodes/PresBox.tsx                 | 28 +------
 .../views/presentationview/PresElementBox.tsx      | 90 +++++++++++-----------
 src/new_fields/Doc.ts                              |  7 +-
 .../authentication/models/current_user_utils.ts    |  5 +-
 12 files changed, 94 insertions(+), 91 deletions(-)

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

diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index d0f1d86cb..3c7caa60b 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -8,7 +8,7 @@ import { ScriptField, ComputedField } from "../../new_fields/ScriptField";
 import { RichTextField } from "../../new_fields/RichTextField";
 import { ImageField } from "../../new_fields/URLField";
 
-export function makeTemplate(doc: Doc): boolean {
+export function makeTemplate(doc: Doc, first: boolean = true): boolean {
     const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc;
     const layout = StrCast(layoutDoc.layout).match(/fieldKey={'[^']*'}/)![0];
     const fieldKey = layout.replace("fieldKey={'", "").replace(/'}$/, "");
@@ -18,9 +18,12 @@ export function makeTemplate(doc: Doc): boolean {
         if (!StrCast(d.title).startsWith("-")) {
             any = Doc.MakeMetadataFieldTemplate(d, Doc.GetProto(layoutDoc)) || any;
         } else if (d.type === DocumentType.COL || d.data instanceof RichTextField) {
-            any = makeTemplate(d) || any;
+            any = makeTemplate(d, false) || any;
         }
     });
+    if (!docs.length && first) {
+        any = Doc.MakeMetadataFieldTemplate(doc, Doc.GetProto(layoutDoc)) || any;
+    }
     if (layoutDoc[fieldKey] instanceof RichTextField || layoutDoc[fieldKey] instanceof ImageField) {
         if (!StrCast(layoutDoc.title).startsWith("-")) {
             any = Doc.MakeMetadataFieldTemplate(layoutDoc, Doc.GetProto(layoutDoc));
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index ce48e1215..0bf944f22 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -1,4 +1,4 @@
-import { Doc } from '../../new_fields/Doc';
+import { Doc, Opt } from '../../new_fields/Doc';
 import { Touchable } from './Touchable';
 import { computed, action, observable } from 'mobx';
 import { Cast } from '../../new_fields/Types';
@@ -11,12 +11,13 @@ import { PositionDocument } from '../../new_fields/documentSchemas';
 ///  DocComponent returns a generic React base class used by views that don't have any data extensions (e.g.,CollectionFreeFormDocumentView, DocumentView, ButtonBox)
 interface DocComponentProps {
     Document: Doc;
+    LayoutDoc?: () => Opt<Doc>;
 }
 export function DocComponent<P extends DocComponentProps, T>(schemaCtor: (doc: Doc) => T) {
     class Component extends Touchable<P> {
         //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
         @computed get Document(): T { return schemaCtor(this.props.Document); }
-        @computed get layoutDoc() { return PositionDocument(Doc.Layout(this.props.Document)); }
+        @computed get layoutDoc() { return PositionDocument(Doc.Layout(this.props.Document, this.props.LayoutDoc?.())); }
     }
     return Component;
 }
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 21c34d047..d21ae32bc 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -55,7 +55,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         this._docXfs.length = 0;
         return docs.map((d, i) => {
             const height = () => this.getDocHeight(d);
-            const width = () => Math.min(d._nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns);
+            const width = () => this.getDocWidth(d);
             const dref = React.createRef<HTMLDivElement>();
             const dxf = () => this.getDocTransform(d, dref.current!);
             this._docXfs.push({ dxf: dxf, width: width, height: height });
@@ -154,11 +154,12 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @computed get onClickHandler() { return ScriptCast(this.Document.onChildClick); }
 
     getDisplayDoc(doc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) {
-        const layoutDoc = Doc.Layout(doc);
+        const layoutDoc = Doc.Layout(doc, this.props.childLayoutTemplate?.());
         const height = () => this.getDocHeight(doc);
         return <ContentFittingDocumentView
             Document={doc}
             DataDocument={dataDoc}
+            LayoutDoc={this.props.childLayoutTemplate}
             LibraryPath={this.props.LibraryPath}
             renderDepth={this.props.renderDepth + 1}
             fitToBox={this.props.fitToBox}
@@ -178,19 +179,26 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             pinToPres={this.props.pinToPres}>
         </ContentFittingDocumentView>;
     }
+
+    getDocWidth(d?: Doc) {
+        if (!d) return 0;
+        const layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
+        const nw = NumCast(layoutDoc._nativeWidth);
+        return Math.min(nw && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns);
+    }
     getDocHeight(d?: Doc) {
         if (!d) return 0;
-        const layoutDoc = Doc.Layout(d);
+        let layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
         const nw = NumCast(layoutDoc._nativeWidth);
         const nh = NumCast(layoutDoc._nativeHeight);
         let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
         if (!layoutDoc.ignoreAspect && !layoutDoc._fitWidth && nw && nh) {
             const aspect = nw && nh ? nh / nw : 1;
-            if (!(d._nativeWidth && !layoutDoc.ignoreAspect && this.props.Document.fillColumn)) wid = Math.min(layoutDoc[WidthSym](), wid);
+            if (!(!layoutDoc.ignoreAspect && this.props.Document.fillColumn)) wid = Math.min(layoutDoc[WidthSym](), wid);
             return wid * aspect;
         }
-        return layoutDoc._fitWidth ? !layoutDoc._nativeHeight ? this.props.PanelHeight() - 2 * this.yMargin :
-            Math.min(wid * NumCast(layoutDoc.scrollHeight, NumCast(layoutDoc._nativeHeight)) / NumCast(layoutDoc._nativeWidth, 1), this.props.PanelHeight() - 2 * this.yMargin) : layoutDoc[HeightSym]();
+        return layoutDoc._fitWidth ? !nh ? this.props.PanelHeight() - 2 * this.yMargin :
+            Math.min(wid * NumCast(layoutDoc.scrollHeight, nh) / (nw || 1), this.props.PanelHeight() - 2 * this.yMargin) : layoutDoc[HeightSym]();
     }
 
     columnDividerDown = (e: React.PointerEvent) => {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index b86cbbdbd..050ca8347 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -43,6 +43,9 @@ export interface ViewDefResult {
     bounds?: ViewDefBounds;
 }
 function toLabel(target: FieldResult<Field>) {
+    if (typeof target === "number" || Number(target)) {
+        return Number(target).toFixed(2).toString();
+    }
     if (target instanceof ObjectField || target instanceof RefField) {
         return target[ToString]();
     }
@@ -254,10 +257,10 @@ export function computeTimelineLayout(
     let prevKey = Math.floor(minTime);
 
     if (sortedKeys.length && scaling * (sortedKeys[0] - prevKey) > 25) {
-        groupNames.push({ type: "text", text: prevKey.toString(), x: x, y: 0, height: fontHeight, fontSize, payload: undefined });
+        groupNames.push({ type: "text", text: toLabel(prevKey), x: x, y: 0, height: fontHeight, fontSize, payload: undefined });
     }
     if (!sortedKeys.length && curTime !== undefined) {
-        groupNames.push({ type: "text", text: curTime.toString(), x: (curTime - minTime) * scaling, zIndex: 1000, color: "orange", y: 0, height: fontHeight, fontSize, payload: undefined });
+        groupNames.push({ type: "text", text: toLabel(curTime), x: (curTime - minTime) * scaling, zIndex: 1000, color: "orange", y: 0, height: fontHeight, fontSize, payload: undefined });
     }
 
     const pivotAxisWidth = NumCast(pivotDoc.pivotTimeWidth, panelDim[1] / 2.5);
@@ -265,7 +268,7 @@ export function computeTimelineLayout(
     let zind = 0;
     sortedKeys.forEach(key => {
         if (curTime !== undefined && curTime > prevKey && curTime <= key) {
-            groupNames.push({ type: "text", text: curTime.toString(), x: (curTime - minTime) * scaling, y: 0, zIndex: 1000, color: "orange", height: fontHeight, fontSize, payload: key });
+            groupNames.push({ type: "text", text: toLabel(curTime), x: (curTime - minTime) * scaling, y: 0, zIndex: 1000, color: "orange", height: fontHeight, fontSize, payload: key });
         }
         const keyDocs = pivotDateGroups.get(key)!;
         x += scaling * (key - prevKey);
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index bd1b6166f..671f5b96e 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -2,7 +2,7 @@ import React = require("react");
 import { action, computed } from "mobx";
 import { observer } from "mobx-react";
 import "react-table/react-table.css";
-import { Doc } from "../../../new_fields/Doc";
+import { Doc, Opt } from "../../../new_fields/Doc";
 import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
 import { NumCast, StrCast } from "../../../new_fields/Types";
 import { emptyFunction, returnEmptyString, returnOne } from "../../../Utils";
@@ -18,6 +18,7 @@ import { TraceMobx } from "../../../new_fields/util";
 interface ContentFittingDocumentViewProps {
     Document?: Doc;
     DataDocument?: Doc;
+    LayoutDoc?: () => Opt<Doc>;
     LibraryPath: Doc[];
     childDocs?: Doc[];
     renderDepth: number;
@@ -42,7 +43,7 @@ interface ContentFittingDocumentViewProps {
 @observer
 export class ContentFittingDocumentView extends React.Component<ContentFittingDocumentViewProps>{
     public get displayName() { return "DocumentView(" + this.props.Document?.title + ")"; } // this makes mobx trace() statements more descriptive
-    private get layoutDoc() { return this.props.Document && Doc.Layout(this.props.Document); }
+    private get layoutDoc() { return this.props.Document && (this.props.LayoutDoc?.() || Doc.Layout(this.props.Document)); }
     private get nativeWidth() { return NumCast(this.layoutDoc?._nativeWidth, this.props.PanelWidth()); }
     private get nativeHeight() { return NumCast(this.layoutDoc?._nativeHeight, this.props.PanelHeight()); }
     @computed get scaling() {
@@ -97,6 +98,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                     <DocumentView {...this.props}
                         Document={this.props.Document}
                         DataDoc={this.props.DataDocument}
+                        LayoutDoc={this.props.LayoutDoc}
                         LibraryPath={this.props.LibraryPath}
                         fitToBox={this.props.fitToBox}
                         onClick={this.props.onClick}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index a274fe8aa..11a33b70a 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -82,10 +82,10 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
         return this.props.DataDoc instanceof Promise ? undefined : this.props.DataDoc;
     }
     get layoutDoc() {
-        if (this.props.DataDoc === undefined && typeof Doc.LayoutField(this.props.Document) !== "string") {
+        if (this.props.DataDoc === undefined && (this.props.LayoutDoc || typeof Doc.LayoutField(this.props.Document) !== "string")) {
             // if there is no dataDoc (ie, we're not rendering a template layout), but this document has a layout document (not a layout string), 
             // then we render the layout document as a template and use this document as the data context for the template layout.
-            return Doc.expandTemplateLayout(Doc.Layout(this.props.Document), this.props.Document);
+            return Doc.expandTemplateLayout(this.props.LayoutDoc?.() || Doc.Layout(this.props.Document), this.props.Document);
         }
         return Doc.Layout(this.props.Document);
     }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index e4ab3e746..36db1ce37 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -43,7 +43,6 @@ import { ScriptingRepl } from '../ScriptingRepl';
 import { DocumentContentsView } from "./DocumentContentsView";
 import "./DocumentView.scss";
 import { FormattedTextBox } from './FormattedTextBox';
-import { FormattedTextBoxComment } from './FormattedTextBoxComment';
 import React = require("react");
 
 
@@ -56,6 +55,7 @@ export interface DocumentViewProps {
     ContainingCollectionDoc: Opt<Doc>;
     Document: Doc;
     DataDoc?: Doc;
+    LayoutDoc?: () => Opt<Doc>;
     LibraryPath: Doc[];
     fitToBox?: boolean;
     onClick?: ScriptField;
@@ -834,6 +834,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             ContainingCollectionDoc={this.props.ContainingCollectionDoc}
             Document={this.props.Document}
             DataDoc={this.props.DataDoc}
+            LayoutDoc={this.props.LayoutDoc}
             fitToBox={this.props.fitToBox}
             LibraryPath={this.props.LibraryPath}
             addDocument={this.props.addDocument}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 7544a5b77..8250f41f3 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -43,6 +43,7 @@ export interface FieldViewProps {
     setVideoBox?: (player: VideoBox) => void;
     ContentScaling: () => number;
     ChromeHeight?: () => number;
+    childLayoutTemplate?: () => Opt<Doc>;
 }
 
 @observer
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 85017d3d4..d4a47c159 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -20,6 +20,7 @@ import { ContextMenuProps } from "../ContextMenuItem";
 import { InkingControl } from "../InkingControl";
 import { FieldView, FieldViewProps } from './FieldView';
 import "./PresBox.scss";
+import { PrefetchProxy } from "../../../new_fields/Proxy";
 
 library.add(faArrowLeft);
 library.add(faArrowRight);
@@ -34,35 +35,14 @@ library.add(faEdit);
 export class PresBox extends React.Component<FieldViewProps> {
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); }
     _childReaction: IReactionDisposer | undefined;
-    _slideshowReaction: IReactionDisposer | undefined;
     @observable _isChildActive = false;
-
     componentDidMount() {
-        const userDoc = CurrentUserUtils.UserDocument;
         this.props.Document._forceRenderEngine = "timeline";
         this.props.Document._replacedChrome = "replaced";
-        this._slideshowReaction = reaction(() => this.props.Document._viewType,
-            (slideshow) => {
-                if (slideshow === CollectionViewType.Stacking || slideshow === undefined) {
-                    let presTemp = Cast(userDoc.presentationTemplate, Doc);
-                    if (presTemp instanceof Promise) {
-                        presTemp.then(presTemp => this.props.Document.childLayout = presTemp);
-                    }
-                    else if (presTemp === undefined) {
-                        presTemp = userDoc.presentationTemplate = Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent", _xMargin: 5, isTemplateDoc: true, isTemplateForField: "data" });
-                    }
-                    else {
-                        this.props.Document.childLayout = presTemp;
-                    }
-                } else {
-                    this.props.Document.childLayout = undefined;
-                }
-            }, { fireImmediately: true });
         this._childReaction = reaction(() => this.childDocs.slice(), (children) => children.forEach((child, i) => child.presentationIndex = i), { fireImmediately: true });
     }
     componentWillUnmount() {
         this._childReaction?.();
-        this._slideshowReaction?.();
     }
 
     @computed get childDocs() { return DocListCast(this.props.Document[this.props.fieldKey]); }
@@ -376,7 +356,6 @@ export class PresBox extends React.Component<FieldViewProps> {
             doc.presBox = this.props.Document;
             doc.presBoxKey = this.props.fieldKey;
             doc.collapsedHeight = hgt;
-            doc._nativeWidth = doc._nativeHeight = undefined;
             const curScale = NumCast(doc.viewScale, null);
             if (curScale === undefined) {
                 doc.viewScale = 1;
@@ -402,6 +381,8 @@ export class PresBox extends React.Component<FieldViewProps> {
         this.props.Document._viewType = Number(e.target.selectedOptions[0].value);
         this.updateMinimize(e, Number(this.props.Document._viewType));
     });
+
+    childLayoutTemplate = () => this.props.Document._viewType === CollectionViewType.Stacking ? Cast(Doc.UserDoc().presentationTemplate, Doc, null) : undefined;
     render() {
         const mode = NumCast(this.props.Document._viewType, CollectionViewType.Invalid);
         this.initializeScaleViews(this.childDocs, mode);
@@ -425,8 +406,7 @@ export class PresBox extends React.Component<FieldViewProps> {
             </div>
             <div className="presBox-listCont" >
                 {mode !== CollectionViewType.Invalid ?
-                    <CollectionView {...this.props} PanelHeight={this.panelHeight}
-                        moveDocument={returnFalse}
+                    <CollectionView {...this.props} PanelHeight={this.panelHeight} moveDocument={returnFalse} childLayoutTemplate={this.childLayoutTemplate}
                         addDocument={this.addDocument} removeDocument={returnFalse} focus={this.selectElement} ScreenToLocalTransform={this.getTransform} />
                     : (null)
                 }
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 52773d466..888707ee3 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -2,19 +2,18 @@ import { library } from '@fortawesome/fontawesome-svg-core';
 import { faFile as fileRegular } from '@fortawesome/free-regular-svg-icons';
 import { faArrowDown, faArrowUp, faFile as fileSolid, faFileDownload, faLocationArrow, faSearch } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, reaction, IReactionDisposer } from "mobx";
+import { action, computed, IReactionDisposer, reaction } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, DocListCast } from "../../../new_fields/Doc";
+import { Doc } from "../../../new_fields/Doc";
 import { documentSchema } from '../../../new_fields/documentSchemas';
 import { Id } from "../../../new_fields/FieldSymbols";
 import { createSchema, makeInterface } from '../../../new_fields/Schema';
-import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { emptyFunction, returnFalse, emptyPath } from "../../../Utils";
-import { DocumentType } from "../../documents/DocumentTypes";
+import { Cast, NumCast } from "../../../new_fields/Types";
+import { emptyFunction, emptyPath, returnFalse } from "../../../Utils";
 import { Transform } from "../../util/Transform";
 import { CollectionViewType } from '../collections/CollectionView';
+import { DocExtendableComponent } from '../DocComponent';
 import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView';
-import { DocComponent, DocExtendableComponent } from '../DocComponent';
 import { FieldView, FieldViewProps } from '../nodes/FieldView';
 import "./PresElementBox.scss";
 import React = require("react");
@@ -50,15 +49,16 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresElementBox, fieldKey); }
 
     _heightDisposer: IReactionDisposer | undefined;
-    @computed get indexInPres() { return NumCast(this.originalLayout?.presentationIndex); }
-    @computed get presentationDoc() { return Cast(this.originalLayout?.presBox, Doc) as Doc; }
-    @computed get originalLayout() { return this.props.Document.expandedTemplate as Doc; }
-    @computed get targetDoc() { return this.originalLayout?.presentationTargetDoc as Doc; }
-    @computed get currentIndex() { return NumCast(this.presentationDoc?._itemIndex); }
+    @computed get indexInPres() { return NumCast(this.presElementDoc?.presentationIndex); }
+    @computed get presBoxDoc() { return Cast(this.presElementDoc?.presBox, Doc) as Doc; }
+    @computed get presElementDoc() { return this.props.Document.expandedTemplate as Doc; }
+    @computed get presLayoutDoc() { return this.props.Document; }
+    @computed get targetDoc() { return this.presElementDoc?.presentationTargetDoc as Doc; }
+    @computed get currentIndex() { return NumCast(this.presBoxDoc?._itemIndex); }
 
     componentDidMount() {
-        this._heightDisposer = reaction(() => [this.originalLayout.embedOpen, this.originalLayout.collapsedHeight],
-            params => this.originalLayout._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true });
+        this._heightDisposer = reaction(() => [this.presElementDoc.embedOpen, this.presElementDoc.collapsedHeight],
+            params => this.presLayoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true });
     }
     componentWillUnmount() {
         this._heightDisposer?.();
@@ -71,13 +71,13 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
     @action
     onHideDocumentUntilPressClick = (e: React.MouseEvent) => {
         e.stopPropagation();
-        this.originalLayout.hideTillShownButton = !this.originalLayout.hideTillShownButton;
-        if (!this.originalLayout.hideTillShownButton) {
+        this.presElementDoc.hideTillShownButton = !this.presElementDoc.hideTillShownButton;
+        if (!this.presElementDoc.hideTillShownButton) {
             if (this.indexInPres >= this.currentIndex && this.targetDoc) {
                 this.targetDoc.opacity = 1;
             }
         } else {
-            if (this.presentationDoc.presStatus && this.indexInPres > this.currentIndex && this.targetDoc) {
+            if (this.presBoxDoc.presStatus && this.indexInPres > this.currentIndex && this.targetDoc) {
                 this.targetDoc.opacity = 0;
             }
         }
@@ -91,14 +91,14 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
     @action
     onHideDocumentAfterPresentedClick = (e: React.MouseEvent) => {
         e.stopPropagation();
-        this.originalLayout.hideAfterButton = !this.originalLayout.hideAfterButton;
-        if (!this.originalLayout.hideAfterButton) {
+        this.presElementDoc.hideAfterButton = !this.presElementDoc.hideAfterButton;
+        if (!this.presElementDoc.hideAfterButton) {
             if (this.indexInPres <= this.currentIndex && this.targetDoc) {
                 this.targetDoc.opacity = 1;
             }
         } else {
-            if (this.originalLayout.fadeButton) this.originalLayout.fadeButton = false;
-            if (this.presentationDoc.presStatus && this.indexInPres < this.currentIndex && this.targetDoc) {
+            if (this.presElementDoc.fadeButton) this.presElementDoc.fadeButton = false;
+            if (this.presBoxDoc.presStatus && this.indexInPres < this.currentIndex && this.targetDoc) {
                 this.targetDoc.opacity = 0;
             }
         }
@@ -112,14 +112,14 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
     @action
     onFadeDocumentAfterPresentedClick = (e: React.MouseEvent) => {
         e.stopPropagation();
-        this.originalLayout.fadeButton = !this.originalLayout.fadeButton;
-        if (!this.originalLayout.fadeButton) {
+        this.presElementDoc.fadeButton = !this.presElementDoc.fadeButton;
+        if (!this.presElementDoc.fadeButton) {
             if (this.indexInPres <= this.currentIndex && this.targetDoc) {
                 this.targetDoc.opacity = 1;
             }
         } else {
-            this.originalLayout.hideAfterButton = false;
-            if (this.presentationDoc.presStatus && (this.indexInPres < this.currentIndex) && this.targetDoc) {
+            this.presElementDoc.hideAfterButton = false;
+            if (this.presBoxDoc.presStatus && (this.indexInPres < this.currentIndex) && this.targetDoc) {
                 this.targetDoc.opacity = 0.5;
             }
         }
@@ -131,11 +131,11 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
     @action
     onNavigateDocumentClick = (e: React.MouseEvent) => {
         e.stopPropagation();
-        this.originalLayout.navButton = !this.originalLayout.navButton;
-        if (this.originalLayout.navButton) {
-            this.originalLayout.showButton = false;
+        this.presElementDoc.navButton = !this.presElementDoc.navButton;
+        if (this.presElementDoc.navButton) {
+            this.presElementDoc.showButton = false;
             if (this.currentIndex === this.indexInPres) {
-                this.props.focus(this.originalLayout);
+                this.props.focus(this.presElementDoc);
             }
         }
     }
@@ -147,13 +147,13 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
     onZoomDocumentClick = (e: React.MouseEvent) => {
         e.stopPropagation();
 
-        this.originalLayout.showButton = !this.originalLayout.showButton;
-        if (!this.originalLayout.showButton) {
-            this.originalLayout.viewScale = 1;
+        this.presElementDoc.showButton = !this.presElementDoc.showButton;
+        if (!this.presElementDoc.showButton) {
+            this.presElementDoc.viewScale = 1;
         } else {
-            this.originalLayout.navButton = false;
+            this.presElementDoc.navButton = false;
             if (this.currentIndex === this.indexInPres) {
-                this.props.focus(this.originalLayout);
+                this.props.focus(this.presElementDoc);
             }
         }
     }
@@ -162,14 +162,14 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
      */
     ScreenToLocalListTransform = (xCord: number, yCord: number) => [xCord, yCord];
 
-    embedHeight = () => this.props.PanelHeight() - NumCast(this.originalLayout.collapsedHeight);
+    embedHeight = () => this.props.PanelHeight() - NumCast(this.presElementDoc.collapsedHeight);
     embedWidth = () => this.props.PanelWidth() - 20;
     /**
      * The function that is responsible for rendering the a preview or not for this
      * presentation element.
      */
     renderEmbeddedInline = () => {
-        return !this.originalLayout.embedOpen || !this.targetDoc ? (null) :
+        return !this.presElementDoc.embedOpen || !this.targetDoc ? (null) :
             <div className="presElementBox-embedded" style={{ height: this.embedHeight() }}>
                 <ContentFittingDocumentView
                     Document={this.targetDoc}
@@ -196,24 +196,24 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
         const treecontainer = this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Tree;
         const className = "presElementBox-item" + (this.currentIndex === this.indexInPres ? " presElementBox-selected" : "");
         const pbi = "presElementBox-interaction";
-        return !this.originalLayout ? (null) : (
+        return !this.presElementDoc ? (null) : (
             <div className={className} key={this.props.Document[Id] + this.indexInPres}
                 style={{ outlineWidth: Doc.IsBrushed(this.targetDoc) ? `1px` : "0px", }}
-                onClick={e => { this.props.focus(this.originalLayout); e.stopPropagation(); }}>
+                onClick={e => { this.props.focus(this.presElementDoc); e.stopPropagation(); }}>
                 {treecontainer ? (null) : <>
                     <strong className="presElementBox-name">
                         {`${this.indexInPres + 1}. ${this.targetDoc?.title}`}
                     </strong>
-                    <button className="presElementBox-closeIcon" onPointerDown={e => e.stopPropagation()} onClick={e => this.props.removeDocument && this.props.removeDocument(this.originalLayout)}>X</button>
+                    <button className="presElementBox-closeIcon" onPointerDown={e => e.stopPropagation()} onClick={e => this.props.removeDocument && this.props.removeDocument(this.presElementDoc)}>X</button>
                     <br />
                 </>}
-                <button title="Zoom" className={pbi + (this.originalLayout.showButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onZoomDocumentClick}><FontAwesomeIcon icon={"search"} /></button>
-                <button title="Navigate" className={pbi + (this.originalLayout.navButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onNavigateDocumentClick}><FontAwesomeIcon icon={"location-arrow"} /></button>
-                <button title="Hide Before" className={pbi + (this.originalLayout.hideTillShownButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onHideDocumentUntilPressClick}><FontAwesomeIcon icon={fileSolid} /></button>
-                <button title="Fade After" className={pbi + (this.originalLayout.fadeButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onFadeDocumentAfterPresentedClick}><FontAwesomeIcon icon={faFileDownload} /></button>
-                <button title="Hide After" className={pbi + (this.originalLayout.hideAfterButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onHideDocumentAfterPresentedClick}><FontAwesomeIcon icon={faFileDownload} /></button>
-                <button title="Group With Up" className={pbi + (this.originalLayout.groupButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={e => { e.stopPropagation(); this.originalLayout.groupButton = !this.originalLayout.groupButton; }}><FontAwesomeIcon icon={"arrow-up"} /></button>
-                <button title="Expand Inline" className={pbi + (this.originalLayout.embedOpen ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={e => { e.stopPropagation(); this.originalLayout.embedOpen = !this.originalLayout.embedOpen; }}><FontAwesomeIcon icon={"arrow-down"} /></button>
+                <button title="Zoom" className={pbi + (this.presElementDoc.showButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onZoomDocumentClick}><FontAwesomeIcon icon={"search"} /></button>
+                <button title="Navigate" className={pbi + (this.presElementDoc.navButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onNavigateDocumentClick}><FontAwesomeIcon icon={"location-arrow"} /></button>
+                <button title="Hide Before" className={pbi + (this.presElementDoc.hideTillShownButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onHideDocumentUntilPressClick}><FontAwesomeIcon icon={fileSolid} /></button>
+                <button title="Fade After" className={pbi + (this.presElementDoc.fadeButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onFadeDocumentAfterPresentedClick}><FontAwesomeIcon icon={faFileDownload} /></button>
+                <button title="Hide After" className={pbi + (this.presElementDoc.hideAfterButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onHideDocumentAfterPresentedClick}><FontAwesomeIcon icon={faFileDownload} /></button>
+                <button title="Group With Up" className={pbi + (this.presElementDoc.groupButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={e => { e.stopPropagation(); this.presElementDoc.groupButton = !this.presElementDoc.groupButton; }}><FontAwesomeIcon icon={"arrow-up"} /></button>
+                <button title="Expand Inline" className={pbi + (this.presElementDoc.embedOpen ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={e => { e.stopPropagation(); this.presElementDoc.embedOpen = !this.presElementDoc.embedOpen; }}><FontAwesomeIcon icon={"arrow-down"} /></button>
 
                 <br style={{ lineHeight: 0.1 }} />
                 {this.renderEmbeddedInline()}
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 1636f4ee7..447dbe3b0 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -701,8 +701,11 @@ export namespace Doc {
     }
 
     // the document containing the view layout information - will be the Document itself unless the Document has
-    // a layout field.  In that case, all layout information comes from there unless overriden by Document  
-    export function Layout(doc: Doc): Doc { return doc[LayoutSym] || doc; }
+    // a layout field or 'layout' is given.  
+    export function Layout(doc: Doc, layout?: Doc): Doc {
+        const overrideLayout = layout && Cast(doc["data-layout[" + layout[Id] + "]"], Doc, null);
+        return overrideLayout || doc[LayoutSym] || doc;
+    }
     export function SetLayout(doc: Doc, layout: Doc | string) { doc[StrCast(doc.layoutKey, "layout")] = layout; }
     export function LayoutField(doc: Doc) { return doc[StrCast(doc.layoutKey, "layout")]; }
     export function LayoutFieldKey(doc: Doc): string { return StrCast(Doc.Layout(doc).layout).split("'")[1]; }
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 0185017ec..ce4f94d83 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -48,7 +48,7 @@ export class CurrentUserUtils {
     // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools
     static setupCreatorButtons(doc: Doc, buttons?: string[]) {
         const notes = CurrentUserUtils.setupNoteTypes(doc);
-        const emptyPresentation = Docs.Create.PresDocument(new List<Doc>(), { title: "Presentation", _viewType: CollectionViewType.Stacking, _chromeStatus: "replaced", showTitle: "title", boxShadow: "0 0" });
+        const emptyPresentation = Docs.Create.PresDocument(new List<Doc>(), { title: "Presentation", _viewType: CollectionViewType.Stacking, _LODdisable: true, _chromeStatus: "replaced", showTitle: "title", boxShadow: "0 0" });
         const emptyCollection = Docs.Create.FreeformDocument([], { _nativeWidth: undefined, _nativeHeight: undefined, _LODdisable: true, _width: 150, _height: 100, title: "freeform" });
         doc.noteTypes = Docs.Create.TreeDocument(notes, { title: "Note Types", _height: 75 });
         doc.activePen = doc;
@@ -270,7 +270,8 @@ export class CurrentUserUtils {
 
     // the initial presentation Doc to use
     static setupDefaultPresentation(doc: Doc) {
-        doc.curPresentation = Docs.Create.PresDocument(new List<Doc>(), { title: "Presentation", _viewType: CollectionViewType.Stacking, _chromeStatus: "replaced", showTitle: "title", boxShadow: "0 0" });
+        doc.presentationTemplate = new PrefetchProxy(Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent", _xMargin: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data" }));
+        doc.curPresentation = Docs.Create.PresDocument(new List<Doc>(), { title: "Presentation", _viewType: CollectionViewType.Stacking, _LODdisable: true, _chromeStatus: "replaced", showTitle: "title", boxShadow: "0 0" });
     }
 
     static setupMobileUploads(doc: Doc) {
-- 
cgit v1.2.3-70-g09d2


From 30f42e403bd8cca4d20fc1b0d1cf28fbfa3a1524 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 12 Feb 2020 14:54:07 -0500
Subject: moved showTitle,etc to use _showTitle,etc

---
 src/client/documents/Documents.ts                       |  8 +++++---
 src/client/views/DocumentButtonBar.tsx                  |  2 +-
 src/client/views/TemplateMenu.tsx                       |  2 +-
 src/client/views/collections/CollectionStackingView.tsx |  4 +---
 src/client/views/collections/CollectionTreeView.tsx     |  4 ++--
 src/client/views/nodes/DocumentView.tsx                 | 14 +++++++-------
 src/new_fields/documentSchemas.ts                       |  6 +++---
 src/server/authentication/models/current_user_utils.ts  |  2 +-
 8 files changed, 21 insertions(+), 21 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index cc18dc0a6..ec5116539 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -70,7 +70,9 @@ export interface DocumentOptions {
     _fitWidth?: boolean;
     _fitToBox?: boolean; // whether a freeformview should zoom/scale to create a shrinkwrapped view of its contents
     _LODdisable?: boolean;
-    dropAction?: dropActionType;
+    _showTitleHover?: string; // 
+    _showTitle?: string; // which field to display in the title area.  leave empty to have no title
+    _showCaption?: string; // which field to display in the caption area.  leave empty to have no caption
     _chromeStatus?: string;
     _viewType?: number;
     _gridGap?: number; // gap between items in masonry view
@@ -82,6 +84,7 @@ export interface DocumentOptions {
     x?: number;
     y?: number;
     z?: number;
+    dropAction?: dropActionType;
     layoutKey?: string;
     type?: string;
     title?: string;
@@ -109,7 +112,6 @@ export interface DocumentOptions {
     documentText?: string;
     borderRounding?: string;
     boxShadow?: string;
-    showTitle?: string;
     sectionFilter?: string; // field key used to determine headings for sections in stacking and masonry views
     schemaColumns?: List<SchemaHeaderField>;
     dockingConfig?: string;
@@ -392,7 +394,7 @@ export namespace Docs {
         Scripting.addGlobal(Buxton);
 
         const delegateKeys = ["x", "y", "layoutKey", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "dropAction", "_annotationOn",
-            "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "showTitle"];
+            "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "_showTitle", "_showCaption", "_showTitleHover"];
 
         /**
          * This function receives the relevant document prototype and uses
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index ee850922a..ff0d2718c 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -301,7 +301,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
         const view0 = this.view0;
         const templates: Map<Template, boolean> = new Map();
         Array.from(Object.values(Templates.TemplateList)).map(template =>
-            templates.set(template, this.props.views.reduce((checked, doc) => checked || doc?.getLayoutPropStr("show" + template.Name) ? true : false, false as boolean)));
+            templates.set(template, this.props.views.reduce((checked, doc) => checked || doc?.getLayoutPropStr("_show" + template.Name) ? true : false, false as boolean)));
         return !view0 ? (null) : <div title="Customize layout" className="documentButtonBar-linkFlyout" ref={this._dragRef}>
             <Flyout anchorPoint={anchorPoints.LEFT_TOP}
                 content={<TemplateMenu docViews={this.props.views.filter(v => v).map(v => v as DocumentView)} templates={templates} />}>
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 64d1e96e1..595c3817e 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -64,7 +64,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
     @undoBatch
     @action
     toggleTemplate = (event: React.ChangeEvent<HTMLInputElement>, template: Template): void => {
-        this.props.docViews.forEach(d => Doc.Layout(d.Document)["show" + template.Name] = event.target.checked ? template.Name.toLowerCase() : "");
+        this.props.docViews.forEach(d => Doc.Layout(d.Document)["_show" + template.Name] = event.target.checked ? template.Name.toLowerCase() : "");
     }
 
     @action
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index d21ae32bc..7d1f2c284 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -40,7 +40,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @computed get sectionFilter() { return StrCast(this.props.Document.sectionFilter); }
     @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc && !pair.layout.isMinimized).map(pair => pair.layout); }
     @computed get xMargin() { return NumCast(this.props.Document._xMargin, 2 * Math.min(this.gridGap, .05 * this.props.PanelWidth())); }
-    @computed get yMargin() { return Math.max(this.props.Document.showTitle && !this.props.Document.showTitleHover ? 30 : 0, NumCast(this.props.Document._yMargin, 0)); } // 2 * this.gridGap)); }
+    @computed get yMargin() { return Math.max(this.props.Document._showTitle && !this.props.Document._showTitleHover ? 30 : 0, NumCast(this.props.Document._yMargin, 0)); } // 2 * this.gridGap)); }
     @computed get gridGap() { return NumCast(this.props.Document._gridGap, 10); }
     @computed get isStackingView() { return BoolCast(this.props.Document.singleColumn, true); }
     @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; }
@@ -369,8 +369,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         if (!e.isPropagationStopped()) {
             const subItems: ContextMenuProps[] = [];
             subItems.push({ description: `${this.props.Document.fillColumn ? "Variable Size" : "Autosize"} Column`, event: () => this.props.Document.fillColumn = !this.props.Document.fillColumn, icon: "plus" });
-            subItems.push({ description: `${this.props.Document.showTitles ? "Hide Titles" : "Show Titles"}`, event: () => this.props.Document.showTitles = !this.props.Document.showTitles ? "title" : "", icon: "plus" });
-            subItems.push({ description: `${this.props.Document.showCaptions ? "Hide Captions" : "Show Captions"}`, event: () => this.props.Document.showCaptions = !this.props.Document.showCaptions ? "caption" : "", icon: "plus" });
             ContextMenu.Instance.addItem({ description: "Stacking Options ...", subitems: subItems, icon: "eye" });
         }
     }
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index be2947dff..e57003f82 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -656,8 +656,8 @@ export class CollectionTreeView extends CollectionSubView(Document) {
 
                 const heroView = ImageDocument(fallbackImg, { title: "heroView", isTemplateDoc: true, isTemplateForField: "hero", }); // this acts like a template doc and a template field ... a little weird, but seems to work?
                 heroView.proto!.layout = ImageBox.LayoutString("hero");
-                heroView.showTitle = "title";
-                heroView.showTitleHover = "titlehover";
+                heroView._showTitle = "title";
+                heroView._showTitleHover = "titlehover";
 
                 Doc.AddDocToList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data",
                     Docs.Create.FontIconDocument({
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 84a4e2649..48df1ea33 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -232,7 +232,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             e.stopPropagation();
             e.preventDefault();
             if (e.key === "†" || e.key === "t") {
-                if (!StrCast(this.layoutDoc.showTitle)) this.layoutDoc.showTitle = "title";
+                if (!StrCast(this.layoutDoc._showTitle)) this.layoutDoc._showTitle = "title";
                 if (!this._titleRef.current) setTimeout(() => this._titleRef.current?.setIsFocused(true), 0);
                 else if (!this._titleRef.current.setIsFocused(true)) { // if focus didn't change, focus on interior text...
                     {
@@ -807,16 +807,16 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     // does Document set a layout prop 
     setsLayoutProp = (prop: string) => this.props.Document[prop] !== this.props.Document["default" + prop[0].toUpperCase() + prop.slice(1)] && this.props.Document["default" + prop[0].toUpperCase() + prop.slice(1)];
     // get the a layout prop by first choosing the prop from Document, then falling back to the layout doc otherwise.
-    getLayoutPropStr = (prop: string) => StrCast(this.setsLayoutProp(prop) ? this.props.Document[prop] : this.layoutDoc[prop]);
+    getLayoutPropStr = (prop: string) => {
+        return StrCast(this.setsLayoutProp(prop) ? this.props.Document[prop] : Cast(this.layoutDoc?.expandedTemplate, Doc, null)?.[prop] || this.layoutDoc[prop]);
+    }
     getLayoutPropNum = (prop: string) => NumCast(this.setsLayoutProp(prop) ? this.props.Document[prop] : this.layoutDoc[prop]);
 
     isSelected = (outsideReaction?: boolean) => SelectionManager.IsSelected(this, outsideReaction);
     select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); };
 
     chromeHeight = () => {
-        const showTitle = StrCast(this.layoutDoc.showTitle);
-        const showTitleHover = StrCast(this.layoutDoc.showTitleHover);
-        return (showTitle && !showTitleHover ? 0 : 0) + 1;
+        return 1;
     }
 
     @computed get finalLayoutKey() {
@@ -874,8 +874,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     @computed get innards() {
         TraceMobx();
-        const showTitle = StrCast(this.getLayoutPropStr("showTitle"));
-        const showTitleHover = StrCast(this.getLayoutPropStr("showTitleHover"));
+        const showTitle = StrCast(this.getLayoutPropStr("_showTitle"));
+        const showTitleHover = StrCast(this.getLayoutPropStr("_showTitleHover"));
         const showCaption = this.getLayoutPropStr("showCaption");
         const showTextTitle = showTitle && (StrCast(this.layoutDoc.layout).indexOf("PresBox") !== -1 || StrCast(this.layoutDoc.layout).indexOf("FormattedTextBox") !== -1) ? showTitle : undefined;
         const searchHighlight = (!this.Document.searchFields ? (null) :
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index 962ef2f4b..81f073855 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -14,6 +14,9 @@ export const documentSchema = createSchema({
     _nativeHeight: "number",    // "
     _width: "number",           // width of document in its container's coordinate system
     _height: "number",          // "
+    _showCaption: "string",      // whether editable caption text is overlayed at the bottom of the document 
+    _showTitle: "string",        // the fieldkey whose contents should be displayed at the top of the document
+    _showTitleHover: "string",   // the showTitle should be shown only on hover
     _freeformLayoutEngine: "string",// the string ID for the layout engine to use to layout freeform view documents
     _LODdisable: "boolean",     // whether to disbale LOD switching for CollectionFreeFormViews
     _pivotField: "string",      // specifies which field should be used as the timeline/pivot axis
@@ -46,9 +49,6 @@ export const documentSchema = createSchema({
     borderRounding: "string",   // border radius rounding of document
     searchFields: "string",     // the search fields to display when this document matches a search in its metadata
     heading: "number",          // the logical layout 'heading' of this document (used by rule provider to stylize h1 header elements, from h2, etc)
-    showCaption: "string",      // whether editable caption text is overlayed at the bottom of the document 
-    showTitle: "string",        // the fieldkey whose contents should be displayed at the top of the document
-    showTitleHover: "string",   // the showTitle should be shown only on hover
     isButton: "boolean",        // whether document functions as a button (overiding native interactions of its content)    
     ignoreClick: "boolean",     // whether documents ignores input clicks (but does not ignore manipulation and other events) 
     scrollToLinkID: "string",   // id of link being traversed. allows this doc to scroll/highlight/etc its link anchor. scrollToLinkID should be set to undefined by this doc after it sets up its scroll,etc.
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index ce4f94d83..fde1c9790 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -271,7 +271,7 @@ export class CurrentUserUtils {
     // the initial presentation Doc to use
     static setupDefaultPresentation(doc: Doc) {
         doc.presentationTemplate = new PrefetchProxy(Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent", _xMargin: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data" }));
-        doc.curPresentation = Docs.Create.PresDocument(new List<Doc>(), { title: "Presentation", _viewType: CollectionViewType.Stacking, _LODdisable: true, _chromeStatus: "replaced", showTitle: "title", boxShadow: "0 0" });
+        doc.curPresentation = Docs.Create.PresDocument(new List<Doc>(), { title: "Presentation", _viewType: CollectionViewType.Stacking, _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" });
     }
 
     static setupMobileUploads(doc: Doc) {
-- 
cgit v1.2.3-70-g09d2


From 5aecc6d75868dcafd0b1bb560ad5a4ad8ab976fa Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 14 Feb 2020 14:25:53 -0500
Subject: cleaned up backgroundColor settings and cluster overrides.  added a
 darkScheme

---
 src/client/documents/Documents.ts                  |  2 +-
 src/client/views/DocumentButtonBar.tsx             |  2 +-
 src/client/views/MainView.tsx                      | 27 ++++++++++++-----
 .../views/collections/CollectionCarouselView.tsx   |  1 +
 .../views/collections/CollectionDockingView.tsx    |  3 +-
 .../views/collections/CollectionSchemaCells.tsx    |  3 +-
 .../views/collections/CollectionStackingView.tsx   |  1 +
 .../views/collections/CollectionTreeView.scss      |  9 ++++--
 .../views/collections/CollectionTreeView.tsx       | 16 ++++++----
 src/client/views/collections/CollectionView.tsx    |  3 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 12 ++++----
 .../collections/collectionFreeForm/MarqueeView.tsx |  3 +-
 .../CollectionMulticolumnView.tsx                  |  1 +
 .../CollectionMultirowView.tsx                     |  1 +
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  7 ++---
 .../views/nodes/ContentFittingDocumentView.tsx     |  5 ++--
 src/client/views/nodes/DocumentView.tsx            | 34 +++++-----------------
 src/client/views/nodes/FieldView.tsx               |  6 ++--
 src/client/views/nodes/FormattedTextBox.tsx        |  3 +-
 19 files changed, 72 insertions(+), 67 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index adcdf260d..53671707e 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -168,7 +168,7 @@ export namespace Docs {
         const TemplateMap: TemplateMap = new Map([
             [DocumentType.TEXT, {
                 layout: { view: FormattedTextBox, dataField: data },
-                options: { _height: 150, backgroundColor: "#f1efeb", defaultBackgroundColor: "#f1efeb" }
+                options: { _height: 150 }
             }],
             [DocumentType.HIST, {
                 layout: { view: HistogramBox, dataField: data },
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index ff0d2718c..2201fe710 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -301,7 +301,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
         const view0 = this.view0;
         const templates: Map<Template, boolean> = new Map();
         Array.from(Object.values(Templates.TemplateList)).map(template =>
-            templates.set(template, this.props.views.reduce((checked, doc) => checked || doc?.getLayoutPropStr("_show" + template.Name) ? true : false, false as boolean)));
+            templates.set(template, this.props.views.reduce((checked, doc) => checked || doc?.props.Document["_show" + template.Name] ? true : false, false as boolean)));
         return !view0 ? (null) : <div title="Customize layout" className="documentButtonBar-linkFlyout" ref={this._dragRef}>
             <Flyout anchorPoint={anchorPoints.LEFT_TOP}
                 content={<TemplateMenu docViews={this.props.views.filter(v => v).map(v => v as DocumentView)} templates={templates} />}>
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 192f3b8fb..ba49a2b53 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -13,7 +13,7 @@ import { Doc, DocListCast, Field, FieldResult, Opt } from '../../new_fields/Doc'
 import { Id } from '../../new_fields/FieldSymbols';
 import { List } from '../../new_fields/List';
 import { listSpec } from '../../new_fields/Schema';
-import { Cast, FieldValue, StrCast } from '../../new_fields/Types';
+import { Cast, FieldValue, StrCast, BoolCast } from '../../new_fields/Types';
 import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
 import { emptyFunction, returnEmptyString, returnFalse, returnOne, returnTrue, Utils, emptyPath } from '../../Utils';
 import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
@@ -43,6 +43,7 @@ import SettingsManager from '../util/SettingsManager';
 import { TraceMobx } from '../../new_fields/util';
 import { RadialMenu } from './nodes/RadialMenu';
 import RichTextMenu from '../util/RichTextMenu';
+import { DocumentType } from '../documents/DocumentTypes';
 
 @observer
 export class MainView extends React.Component {
@@ -56,8 +57,9 @@ export class MainView extends React.Component {
     @observable private _panelHeight: number = 0;
     @observable private _flyoutTranslate: boolean = true;
     @observable public flyoutWidth: number = 250;
+    private get darkScheme() { return BoolCast(Cast(this.userDoc.activeWorkspace, Doc, null)?.darkScheme); }
 
-    @computed private get userDoc() { return CurrentUserUtils.UserDocument; }
+    @computed private get userDoc() { return Doc.UserDoc(); }
     @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeWorkspace, Doc)) : CurrentUserUtils.GuestWorkspace; }
     @computed public get mainFreeform(): Opt<Doc> { return (docs => (docs && docs.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); }
     @computed public get sidebarButtonsDoc() { return Cast(CurrentUserUtils.UserDocument.sidebarButtons, Doc) as Doc; }
@@ -207,7 +209,6 @@ export class MainView extends React.Component {
             _width: this._panelWidth * .7,
             _height: this._panelHeight,
             title: "Collection " + workspaceCount,
-            backgroundColor: "white"
         };
         const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions);
         Doc.AddDocToList(Doc.GetProto(CurrentUserUtils.UserDocument.documents as Doc), "data", freeformDoc);
@@ -273,6 +274,16 @@ export class MainView extends React.Component {
     getPHeight = () => this._panelHeight;
     getContentsHeight = () => this._panelHeight - this._buttonBarHeight;
 
+    childBackgroundColor = (doc: Doc) => {
+        if (this.darkScheme) {
+            return doc.type === DocumentType.TEXT ? "#112423" : "black";
+        }
+        return doc.type === DocumentType.TEXT ? "#f1efeb" :
+            doc.type === DocumentType.COL && doc._viewType === CollectionViewType.Tree ? "lightgray" : "white";
+    }
+    sidebarBackgroundColor = (doc: Doc) => {
+        return this.childBackgroundColor(doc);
+    }
     @computed get mainDocView() {
         return <DocumentView Document={this.mainContainer!}
             DataDoc={undefined}
@@ -281,13 +292,13 @@ export class MainView extends React.Component {
             addDocTab={this.addDocTabFunc}
             pinToPres={emptyFunction}
             onClick={undefined}
+            backgroundColor={this.childBackgroundColor}
             removeDocument={undefined}
             ScreenToLocalTransform={Transform.Identity}
             ContentScaling={returnOne}
             PanelWidth={this.getPWidth}
             PanelHeight={this.getPHeight}
             renderDepth={0}
-            backgroundColor={returnEmptyString}
             focus={emptyFunction}
             parentActive={returnTrue}
             whenActiveChanged={emptyFunction}
@@ -366,7 +377,7 @@ export class MainView extends React.Component {
     mainContainerXf = () => new Transform(0, -this._buttonBarHeight, 1);
 
     @computed get flyout() {
-        const sidebarContent = this.userDoc && this.userDoc.sidebarContainer;
+        const sidebarContent = this.userDoc?.sidebarContainer;
         if (!(sidebarContent instanceof Doc)) {
             return (null);
         }
@@ -388,7 +399,7 @@ export class MainView extends React.Component {
                     PanelHeight={this.getPHeight}
                     renderDepth={0}
                     focus={emptyFunction}
-                    backgroundColor={returnEmptyString}
+                    backgroundColor={this.sidebarBackgroundColor}
                     parentActive={returnTrue}
                     whenActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
@@ -414,7 +425,7 @@ export class MainView extends React.Component {
                     PanelHeight={this.getContentsHeight}
                     renderDepth={0}
                     focus={emptyFunction}
-                    backgroundColor={returnEmptyString}
+                    backgroundColor={this.sidebarBackgroundColor}
                     parentActive={returnTrue}
                     whenActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
@@ -437,7 +448,7 @@ export class MainView extends React.Component {
     @computed get mainContent() {
         const sidebar = this.userDoc && this.userDoc.sidebarContainer;
         return !this.userDoc || !(sidebar instanceof Doc) ? (null) : (
-            <div className="mainView-mainContent" >
+            <div className="mainView-mainContent" style={{ color: this.darkScheme ? "lightGray" : "black" }} >
                 <div className="mainView-flyoutContainer" onPointerLeave={this.pointerLeaveDragger} style={{ width: this.flyoutWidth }}>
                     <div className="mainView-libraryHandle" onPointerDown={this.onPointerDown} onPointerOver={this.pointerOverDragger}
                         style={{ backgroundColor: `${StrCast(sidebar.backgroundColor, "lightGray")}` }} >
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 3c86bd799..226a1c813 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -52,6 +52,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
             <div>
                 <div className="collectionCarouselView-image">
                     <ContentFittingDocumentView {...this.props}
+                        backgroundColor={this.props.backgroundColor}
                         Document={this.childLayoutPairs[index].layout}
                         DataDocument={this.childLayoutPairs[index].data}
                         PanelHeight={this.panelHeight}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index cb413b3e3..0b7dbea7c 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -599,6 +599,7 @@ interface DockedFrameProps {
     dataDocumentId: FieldId;
     glContainer: any;
     libraryPath: (FieldId[]);
+    backgroundColor?: (doc:Doc) => string| undefined;
     //collectionDockingView: CollectionDockingView
 }
 @observer
@@ -756,7 +757,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             parentActive={returnTrue}
             whenActiveChanged={emptyFunction}
             focus={emptyFunction}
-            backgroundColor={returnEmptyString}
+            backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
             addDocTab={this.addDocTab}
             pinToPres={DockedFrameRenderer.PinDoc}
             ContainingCollectionView={undefined}
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index caffa7eb1..a3b1b5ec0 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -37,7 +37,8 @@ export interface CellProps {
     renderDepth: number;
     addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
     pinToPres: (document: Doc) => void;
-    moveDocument: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean;
+    moveDocument: (document: Doc, targetCollection: Doc | undefined, 
+    addDocument: (document: Doc) => boolean) => boolean;
     isFocused: boolean;
     changeFocusedCellByIndex: (row: number, col: number) => void;
     setIsEditing: (isEditing: boolean) => void;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 7d1f2c284..055035b3e 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -159,6 +159,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         return <ContentFittingDocumentView
             Document={doc}
             DataDocument={dataDoc}
+            backgroundColor={this.props.backgroundColor}
             LayoutDoc={this.props.childLayoutTemplate}
             LibraryPath={this.props.LibraryPath}
             renderDepth={this.props.renderDepth + 1}
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index 2fa6813d7..6ebe81545 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -63,7 +63,9 @@
     font-size: 8pt;
     margin-left: 3px;
     display: none;
-    background: lightgray;
+}
+.collectionTreeView-keyHeader:hover {
+    background: #797777;
 }
 
 .collectionTreeView-subtitle {
@@ -84,9 +86,11 @@
 .treeViewItem-openRight {
     display: none;
     height: 17px;
-    background: gray;
     width: 15px;
 }
+.treeViewItem-openRight:hover {
+    background: #797777;
+}
 
 .treeViewItem-border {
     display: inherit;
@@ -101,7 +105,6 @@
     .treeViewItem-openRight {
         display: inline-block;
         height: 17px;
-        background: #a8a7a7;
         width: 15px;
 
         // display: inline;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index a160dcc62..e2b3cc425 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -56,6 +56,7 @@ export interface TreeViewProps {
     indentDocument?: () => void;
     outdentDocument?: () => void;
     ScreenToLocalTransform: () => Transform;
+    backgroundColor?: (doc: Doc) => string | undefined;
     outerXf: () => { translateX: number, translateY: number };
     treeViewId: Doc;
     parentKey: string;
@@ -289,7 +290,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 const addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
                 contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] :
                     DocListCast(contents), this.props.treeViewId, doc, undefined, key, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
-                    this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active,
+                    this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active,
                     this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen,
                     [...this.props.renderedIds, doc[Id]], this.props.libraryPath, this.props.onCheckedClick);
             } else {
@@ -332,7 +333,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 {!docs ? (null) :
                     TreeView.GetChildElements(docs, this.props.treeViewId, Doc.Layout(this.props.document),
                         this.templateDataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
-                        this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform,
+                        this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform,
                         this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen,
                         [...this.props.renderedIds, this.props.document[Id]], this.props.libraryPath, this.props.onCheckedClick)}
             </ul >;
@@ -348,6 +349,7 @@ class TreeView extends React.Component<TreeViewProps> {
                     DataDocument={this.templateDataDoc}
                     LibraryPath={emptyPath}
                     renderDepth={this.props.renderDepth + 1}
+                    backgroundColor={this.props.backgroundColor}
                     fitToBox={this.boundsOfCollectionDocument !== undefined}
                     PanelWidth={this.docWidth}
                     PanelHeight={this.docHeight}
@@ -384,7 +386,7 @@ class TreeView extends React.Component<TreeViewProps> {
     @computed
     get renderBullet() {
         const checked = this.props.document.type === DocumentType.COL ? undefined : this.props.onCheckedClick ? (this.props.document.treeViewChecked ? this.props.document.treeViewChecked : "unchecked") : undefined;
-        return <div className="bullet" title="view inline" onClick={this.bulletClick} style={{ color: StrCast(this.props.document.color, checked === "unchecked" ? "white" : "black"), opacity: 0.4 }}>
+        return <div className="bullet" title="view inline" onClick={this.bulletClick} style={{ color: StrCast(this.props.document.color, checked === "unchecked" ? "white" : "inherit"), opacity: 0.4 }}>
             {<FontAwesomeIcon icon={checked === "check" ? "check" : (checked === "x" ? "times" : checked === "unchecked" ? "square" : !this.treeViewOpen ? (this.childDocs ? "caret-square-right" : "caret-right") : (this.childDocs ? "caret-square-down" : "caret-down"))} />}
         </div>;
     }
@@ -415,7 +417,7 @@ class TreeView extends React.Component<TreeViewProps> {
         return <>
             <div className="docContainer" title="click to edit title" id={`docContainer-${this.props.parentKey}`} ref={reference} onPointerDown={onItemDown}
                 style={{
-                    color: this.props.document.isMinimized ? "red" : "black",
+                    color: this.props.document.isMinimized ? "red" : "inherit",
                     background: Doc.IsHighlighted(this.props.document) ? "orange" : Doc.IsBrushed(this.props.document) ? "#06121212" : "0",
                     fontWeight: this.props.document.searchMatch ? "bold" : undefined,
                     outline: BoolCast(this.props.document.workspaceBrush) ? "dashed 1px #06123232" : undefined,
@@ -456,6 +458,7 @@ class TreeView extends React.Component<TreeViewProps> {
         dropAction: dropActionType,
         addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string) => boolean,
         pinToPres: (document: Doc) => void,
+        backgroundColor: undefined | ((document: Doc) => string | undefined),
         screenToLocalXf: () => Transform,
         outerXf: () => { translateX: number, translateY: number },
         active: (outsideReaction?: boolean) => boolean,
@@ -561,6 +564,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 renderDepth={renderDepth}
                 deleteDoc={remove}
                 addDocument={addDocument}
+                backgroundColor={backgroundColor}
                 panelWidth={rowWidth}
                 panelHeight={rowHeight}
                 ChromeHeight={ChromeHeight}
@@ -714,7 +718,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
         const moveDoc = (d: Doc, target: Doc | undefined, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc);
         return !this.childDocs ? (null) : (
             <div className="collectionTreeView-dropTarget" id="body"
-                style={{ background: StrCast(this.props.Document.backgroundColor, "lightgray"), paddingTop: `${NumCast(this.props.Document._yMargin, 20)}px` }}
+                style={{ background: this.props.backgroundColor?.(this.props.Document), paddingTop: `${NumCast(this.props.Document._yMargin, 20)}px` }}
                 onContextMenu={this.onContextMenu}
                 onWheel={(e: React.WheelEvent) => this._mainEle && this._mainEle.scrollHeight > this._mainEle.clientHeight && e.stopPropagation()}
                 onDrop={this.onTreeDrop}
@@ -737,7 +741,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                 <ul className="no-indent" style={{ width: "max-content" }} >
                     {
                         TreeView.GetChildElements(this.childDocs, this.props.Document, this.props.Document, this.props.DataDoc, this.props.fieldKey, this.props.ContainingCollectionDoc, undefined, addDoc, this.remove,
-                            moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform,
+                            moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform,
                             this.outerXf, this.props.active, this.props.PanelWidth, this.props.ChromeHeight, this.props.renderDepth, () => BoolCast(this.props.Document.treeViewHideHeaderFields),
                             BoolCast(this.props.Document.treeViewPreventOpen), [], this.props.LibraryPath, ScriptCast(this.props.Document.onCheckedClick))
                     }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 39ce4d6e8..be971eda6 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -38,6 +38,7 @@ import { CollectionViewBaseChrome } from './CollectionViewChromes';
 import { CollectionTimeView } from './CollectionTimeView';
 import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView';
 import { List } from '../../../new_fields/List';
+import { SubCollectionViewProps } from './CollectionSubView';
 export const COLLECTION_BORDER_WIDTH = 2;
 const path = require('path');
 library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faEllipsisV, faImage, faEye as any, faCopy);
@@ -177,7 +178,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
     }
 
     private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => {
-        const props = { ...this.props, ...renderProps, ChromeHeight: this.chromeHeight, CollectionView: this, annotationsKey: "" };
+        const props: SubCollectionViewProps = { ...this.props, ...renderProps, ChromeHeight: this.chromeHeight, CollectionView: this, annotationsKey: "" };
         switch (type) {
             case CollectionViewType.Schema: return (<CollectionSchemaView key="collview" {...props} />);
             case CollectionViewType.Docking: return (<CollectionDockingView key="collview" {...props} />);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index e1854fc2d..969d6b3c8 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -10,7 +10,7 @@ import { Id } from "../../../../new_fields/FieldSymbols";
 import { InkTool } from "../../../../new_fields/InkField";
 import { createSchema, listSpec, makeInterface } from "../../../../new_fields/Schema";
 import { ScriptField } from "../../../../new_fields/ScriptField";
-import { Cast, NumCast, ScriptCast, StrCast } from "../../../../new_fields/Types";
+import { Cast, NumCast, ScriptCast, BoolCast, StrCast } from "../../../../new_fields/Types";
 import { TraceMobx } from "../../../../new_fields/util";
 import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
 import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils";
@@ -206,6 +206,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     }
 
     @undoBatch
+    @action
     updateClusters(useClusters: boolean) {
         this.props.Document.useClusters = useClusters;
         this._clusterSets.length = 0;
@@ -243,7 +244,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                 docs.map(doc => this._clusterSets[doc.cluster = NumCast(docFirst.cluster)].push(doc));
             }
             childLayouts.map(child => !this._clusterSets.some((set, i) => Doc.IndexOf(child, set) !== -1 && child.cluster === i) && this.updateCluster(child));
-            childLayouts.map(child => Doc.GetProto(child).clusterStr = child.cluster?.toString());
         }
     }
 
@@ -279,16 +279,16 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     }
 
     getClusterColor = (doc: Doc) => {
-        let clusterColor = "";
+        let clusterColor = this.props.backgroundColor?.(doc);
         const cluster = NumCast(doc.cluster);
         if (this.Document.useClusters) {
             if (this._clusterSets.length <= cluster) {
                 setTimeout(() => this.updateCluster(doc), 0);
             } else {
                 // choose a cluster color from a palette
-                const colors = ["#da42429e", "#31ea318c", "#8c4000", "#4a7ae2c4", "#d809ff", "#ff7601", "#1dffff", "yellow", "#1b8231f2", "#000000ad"];
+                const colors = ["#da42429e", "#31ea318c", "rgba(197, 87, 20, 0.55)", "#4a7ae2c4", "rgba(216, 9, 255, 0.5)", "#ff7601", "#1dffff", "yellow", "rgba(27, 130, 49, 0.55)", "rgba(0, 0, 0, 0.268)"];
                 clusterColor = colors[cluster % colors.length];
-                const set = this._clusterSets[cluster] && this._clusterSets[cluster].filter(s => s.backgroundColor && (s.backgroundColor !== s.defaultBackgroundColor));
+                const set = this._clusterSets[cluster]?.filter(s => s.backgroundColor);
                 // override the cluster color with an explicitly set color on a non-background document.  then override that with an explicitly set color on a background document
                 set && set.filter(s => !s.isBackground).map(s => clusterColor = StrCast(s.backgroundColor));
                 set && set.filter(s => s.isBackground).map(s => clusterColor = StrCast(s.backgroundColor));
@@ -709,6 +709,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
     @computed get libraryPath() { return this.props.LibraryPath ? [...this.props.LibraryPath, this.props.Document] : []; }
     @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
+    backgroundHalo = () => BoolCast(this.Document.useClusters);
 
     getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps {
         return {
@@ -728,6 +729,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             ContainingCollectionDoc: this.props.Document,
             focus: this.focusDocument,
             backgroundColor: this.getClusterColor,
+            backgroundHalo: this.backgroundHalo,
             parentActive: this.props.active,
             bringToFront: this.bringToFront,
             zoomToScale: this.zoomToScale,
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 4b0855635..85cda4ecb 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -308,8 +308,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             y: bounds.top,
             _panX: 0,
             _panY: 0,
-            backgroundColor: this.props.isAnnotationOverlay ? "#00000015" : "white",
-            defaultBackgroundColor: this.props.isAnnotationOverlay ? "#00000015" : "white",
+            backgroundColor: this.props.isAnnotationOverlay ? "#00000015" : undefined,
             _width: bounds.width,
             _height: bounds.height,
             _LODdisable: true,
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 7d8de0db4..db5673573 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -207,6 +207,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
             {...this.props}
             Document={layout}
             DataDocument={layout.resolvedDataDoc as Doc}
+            backgroundColor={this.props.backgroundColor}
             CollectionDoc={this.props.Document}
             PanelWidth={width}
             PanelHeight={height}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index ec05443e5..630a178cf 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -208,6 +208,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
             {...this.props}
             Document={layout}
             DataDocument={layout.resolvedDataDoc as Doc}
+            backgroundColor={this.props.backgroundColor}
             CollectionDoc={this.props.Document}
             PanelWidth={width}
             PanelHeight={height}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 3c27ac9a1..53d17b580 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -61,15 +61,12 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     }
 
     contentScaling = () => this.nativeWidth > 0 && !this.props.Document.ignoreAspect && !this.props.fitToBox ? this.width / this.nativeWidth : 1;
-    clusterColorFunc = (doc: Doc) => this.clusterColor;
     panelWidth = () => (this.dataProvider?.width || this.props.PanelWidth());
     panelHeight = () => (this.dataProvider?.height || this.props.PanelHeight());
     getTransform = (): Transform => this.props.ScreenToLocalTransform()
         .translate(-this.X, -this.Y)
         .scale(1 / this.contentScaling())
 
-    @computed
-    get clusterColor() { return this.props.backgroundColor(this.props.Document); }
     focusDoc = (doc: Doc) => this.props.focus(doc, false);
     render() {
         TraceMobx();
@@ -78,7 +75,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 boxShadow:
                     this.layoutDoc.opacity === 0 ? undefined :  // if it's not visible, then no shadow
                         this.layoutDoc.z ? `#9c9396  ${StrCast(this.layoutDoc.boxShadow, "10px 10px 0.9vw")}` :  // if it's a floating doc, give it a big shadow
-                            this.clusterColor ? (`${this.clusterColor} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(this.layoutDoc.isBackground ? 100 : 50) / this.props.ContentScaling()}px`)}`) :  // if it's just in a cluster, make the shadown roughly match the cluster border extent
+                            this.props.backgroundHalo?.() ? (`${this.props.backgroundColor?.(this.props.Document)} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(this.layoutDoc.isBackground ? 100 : 50) / this.props.ContentScaling()}px`)}`) :  // if it's just in a cluster, make the shadown roughly match the cluster border extent
                                 this.layoutDoc.isBackground ? undefined :  // if it's a background & has a cluster color, make the shadow spread really big
                                     StrCast(this.layoutDoc.boxShadow, ""),
                 borderRadius: StrCast(Doc.Layout(this.layoutDoc).borderRounding),
@@ -96,7 +93,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 dragDivName={"collectionFreeFormDocumentView-container"}
                 ContentScaling={this.contentScaling}
                 ScreenToLocalTransform={this.getTransform}
-                backgroundColor={this.clusterColorFunc}
+                backgroundColor={this.props.backgroundColor}
                 PanelWidth={this.panelWidth}
                 PanelHeight={this.panelHeight}
             /> : <ContentFittingDocumentView {...this.props}
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 5c449026e..387da88f5 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -6,7 +6,7 @@ import { Doc, Opt } from "../../../new_fields/Doc";
 import { ScriptField } from "../../../new_fields/ScriptField";
 import { NumCast, StrCast } from "../../../new_fields/Types";
 import { TraceMobx } from "../../../new_fields/util";
-import { emptyFunction, returnEmptyString, returnOne } from "../../../Utils";
+import { emptyFunction, returnOne } from "../../../Utils";
 import { Transform } from "../../util/Transform";
 import { CollectionView } from "../collections/CollectionView";
 import '../DocumentDecorations.scss';
@@ -27,6 +27,7 @@ interface ContentFittingDocumentViewProps {
     CollectionView?: CollectionView;
     CollectionDoc?: Doc;
     onClick?: ScriptField;
+    backgroundColor?: (doc: Doc) => string | undefined;
     getTransform: () => Transform;
     addDocument?: (document: Doc) => boolean;
     moveDocument?: (document: Doc, target: Doc | undefined, addDoc: ((doc: Doc) => boolean)) => boolean;
@@ -86,6 +87,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         LibraryPath={this.props.LibraryPath}
                         fitToBox={this.props.fitToBox}
                         onClick={this.props.onClick}
+                        backgroundColor={this.props.backgroundColor}
                         addDocument={this.props.addDocument}
                         removeDocument={this.props.removeDocument}
                         moveDocument={this.props.moveDocument}
@@ -101,7 +103,6 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         PanelWidth={this.PanelWidth}
                         PanelHeight={this.PanelHeight}
                         focus={this.props.focus || emptyFunction}
-                        backgroundColor={returnEmptyString}
                         bringToFront={emptyFunction}
                         dontRegisterView={this.props.dontRegisterView}
                         zoomToScale={emptyFunction}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index ef065f51d..52928e8cb 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -77,7 +77,8 @@ export interface DocumentViewProps {
     addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string, libraryPath?: Doc[]) => boolean;
     pinToPres: (document: Doc) => void;
     zoomToScale: (scale: number) => void;
-    backgroundColor: (doc: Doc) => string | undefined;
+    backgroundHalo?: () => boolean;
+    backgroundColor?: (doc: Doc) => string | undefined;
     getScale: () => number;
     animateBetweenIcon?: (maximize: boolean, target: number[]) => void;
     ChromeHeight?: () => number;
@@ -295,12 +296,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             this._downX = touch.clientX;
             this._downY = touch.clientY;
             if (!e.nativeEvent.cancelBubble) {
-                this._hitTemplateDrag = false;
-                for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) {
-                    if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") {
-                        this._hitTemplateDrag = true;
-                    }
-                }
                 if ((this.active || this.Document.onDragStart || this.Document.onClick) && !e.ctrlKey && !this.Document.lockedPosition && !this.Document.inOverlay) e.stopPropagation();
                 this.removeMoveListeners();
                 this.addMoveListeners();
@@ -778,14 +773,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         });
     }
 
-    // does Document set a layout prop 
-    setsLayoutProp = (prop: string) => this.props.Document[prop] !== this.props.Document["default" + prop[0].toUpperCase() + prop.slice(1)] && this.props.Document["default" + prop[0].toUpperCase() + prop.slice(1)];
-    // get the a layout prop by first choosing the prop from Document, then falling back to the layout doc otherwise.
-    getLayoutPropStr = (prop: string) => {
-        return StrCast(this.setsLayoutProp(prop) ? this.props.Document[prop] : Cast(this.layoutDoc?.expandedTemplate, Doc, null)?.[prop] || this.layoutDoc[prop]);
-    }
-    getLayoutPropNum = (prop: string) => NumCast(this.setsLayoutProp(prop) ? this.props.Document[prop] : this.layoutDoc[prop]);
-
     isSelected = (outsideReaction?: boolean) => SelectionManager.IsSelected(this, outsideReaction);
     select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); };
 
@@ -848,9 +835,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     @computed get innards() {
         TraceMobx();
-        const showTitle = StrCast(this.getLayoutPropStr("_showTitle"));
-        const showTitleHover = StrCast(this.getLayoutPropStr("_showTitleHover"));
-        const showCaption = this.getLayoutPropStr("_showCaption");
+        const showTitle = StrCast(this.layoutDoc._showTitle);
+        const showTitleHover = StrCast(this.layoutDoc._showTitleHover);
+        const showCaption = StrCast(this.layoutDoc._showCaption);
         const showTextTitle = showTitle && (StrCast(this.layoutDoc.layout).indexOf("PresBox") !== -1 || StrCast(this.layoutDoc.layout).indexOf("FormattedTextBox") !== -1) ? showTitle : undefined;
         const searchHighlight = (!this.Document.searchFields ? (null) :
             <div className="documentView-searchHighlight">
@@ -921,14 +908,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     render() {
         if (!(this.props.Document instanceof Doc)) return (null);
-        const colorSet = this.setsLayoutProp("backgroundColor");
-        const clusterCol = this.props.ContainingCollectionDoc && this.props.ContainingCollectionDoc.clusterOverridesDefaultBackground;
-        const backgroundColor = (clusterCol && !colorSet) ?
-            this.props.backgroundColor(this.Document) || StrCast(this.layoutDoc.backgroundColor) :
-            StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.Document);
-
+        const backgroundColor = StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor?.(this.Document);
         const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document);
-        const borderRounding = this.getLayoutPropStr("borderRounding");
+        const borderRounding = this.layoutDoc.borderRounding;
         const localScale = fullDegree;
 
         const highlightColors = ["transparent", "maroon", "maroon", "yellow", "magenta", "cyan", "orange"];
@@ -943,7 +925,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 transform: this._animate ? `scale(${this._animate})` : undefined,
                 transition: !this._animate ? StrCast(this.Document.transition) : this._animate < 1 ? "transform 0.5s ease-in" : "transform 0.5s ease-out",
                 pointerEvents: this.ignorePointerEvents ? "none" : "all",
-                color: StrCast(this.Document.color),
+                color: StrCast(this.Document.color, "inherit"),
                 outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px",
                 border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined,
                 boxShadow: this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined,
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 8250f41f3..00f00dd52 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -3,14 +3,13 @@ import { computed } from "mobx";
 import { observer } from "mobx-react";
 import { DateField } from "../../../new_fields/DateField";
 import { Doc, FieldResult, Opt } from "../../../new_fields/Doc";
-import { IconField } from "../../../new_fields/IconField";
 import { List } from "../../../new_fields/List";
-import { AudioField, ImageField, VideoField } from "../../../new_fields/URLField";
+import { ScriptField } from "../../../new_fields/ScriptField";
+import { AudioField, VideoField } from "../../../new_fields/URLField";
 import { Transform } from "../../util/Transform";
 import { CollectionView } from "../collections/CollectionView";
 import { AudioBox } from "./AudioBox";
 import { VideoBox } from "./VideoBox";
-import { ScriptField } from "../../../new_fields/ScriptField";
 
 //
 // these properties get assigned through the render() method of the DocumentView when it creates this node.
@@ -34,6 +33,7 @@ export interface FieldViewProps {
     pinToPres: (document: Doc) => void;
     removeDocument?: (document: Doc) => boolean;
     moveDocument?: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean;
+    backgroundColor?: (document: Doc) => string | undefined;
     ScreenToLocalTransform: () => Transform;
     active: (outsideReaction?: boolean) => boolean;
     whenActiveChanged: (isActive: boolean) => void;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 2fb61f9db..3c64b3974 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -186,7 +186,6 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
             tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 5000 - 1000)));
             this._applyingChange = true;
             if (!this.props.Document._textTemplate || Doc.GetProto(this.props.Document) === this.dataDoc) {
-                this.dataDoc[this.props.fieldKey + "-lastModified"] && (this.dataDoc[this.props.fieldKey + "-backgroundColor"] = "lightGray");
                 this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
                 this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON()), state.doc.textBetween(0, state.doc.content.size, "\n\n"));
             }
@@ -1075,7 +1074,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
             <div className={`formattedTextBox-cont`} ref={this._ref}
                 style={{
                     height: this.layoutDoc._autoHeight ? "max-content" : undefined,
-                    background: this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : undefined,
+                    background: this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"]),
                     opacity: this.props.hideOnLeave ? (this._entered ? 1 : 0.1) : 1,
                     color: this.props.hideOnLeave ? "white" : "inherit",
                     pointerEvents: interactive ? "none" : "all",
-- 
cgit v1.2.3-70-g09d2


From b42e1e1e2da941955d7751b6003f18fecd5f2f8d Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Sun, 16 Feb 2020 12:22:10 -0500
Subject: collection sub view and google authentication manager cleanup,
 deleteAssets route added

---
 src/client/apis/GoogleAuthenticationManager.tsx    |  46 ++--
 .../views/collections/CollectionCarouselView.tsx   |  28 +--
 .../views/collections/CollectionLinearView.tsx     |   2 +-
 .../collections/CollectionMasonryViewFieldRow.tsx  |   2 +-
 .../views/collections/CollectionSchemaView.tsx     |   7 +-
 .../views/collections/CollectionStackingView.tsx   |  12 +-
 .../CollectionStackingViewFieldColumn.tsx          |   2 +-
 src/client/views/collections/CollectionSubView.tsx | 264 +++++++++++----------
 .../views/collections/CollectionTreeView.tsx       |   6 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  10 +-
 .../CollectionMulticolumnView.tsx                  |   6 +-
 .../CollectionMultirowView.tsx                     |   6 +-
 src/server/ApiManagers/DeleteManager.ts            |  31 +--
 13 files changed, 213 insertions(+), 209 deletions(-)

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

diff --git a/src/client/apis/GoogleAuthenticationManager.tsx b/src/client/apis/GoogleAuthenticationManager.tsx
index ce1277667..417dc3c3b 100644
--- a/src/client/apis/GoogleAuthenticationManager.tsx
+++ b/src/client/apis/GoogleAuthenticationManager.tsx
@@ -12,8 +12,8 @@ const prompt = "Paste authorization code here...";
 @observer
 export default class GoogleAuthenticationManager extends React.Component<{}> {
     public static Instance: GoogleAuthenticationManager;
-    @observable private openState = false;
     private authenticationLink: Opt<string> = undefined;
+    @observable private openState = false;
     @observable private authenticationCode: Opt<string> = undefined;
     @observable private clickedState = false;
     @observable private success: Opt<boolean> = undefined;
@@ -39,24 +39,18 @@ export default class GoogleAuthenticationManager extends React.Component<{}> {
                 const disposer = reaction(
                     () => this.authenticationCode,
                     async authenticationCode => {
-                        if (!authenticationCode) {
-                            return;
+                        if (authenticationCode) {
+                            disposer();
+                            const { access_token, avatar, name } = await Networking.PostToServer("/writeGoogleAccessToken", { authenticationCode });
+                            runInAction(() => {
+                                this.avatar = avatar;
+                                this.username = name;
+                                this.hasBeenClicked = false;
+                                this.success = false;
+                            });
+                            this.beginFadeout();
+                            resolve(access_token);
                         }
-                        const { access_token, avatar, name } = await Networking.PostToServer(
-                            "/writeGoogleAccessToken",
-                            { authenticationCode }
-                        );
-                        runInAction(() => {
-                            this.avatar = avatar;
-                            this.username = name;
-                        });
-                        this.beginFadeout();
-                        disposer();
-                        resolve(access_token);
-                        action(() => {
-                            this.hasBeenClicked = false;
-                            this.success = false;
-                        });
                     }
                 );
             });
@@ -86,26 +80,20 @@ export default class GoogleAuthenticationManager extends React.Component<{}> {
         GoogleAuthenticationManager.Instance = this;
     }
 
-    private handleClick = () => {
-        window.open(this.authenticationLink);
-        setTimeout(() => this.hasBeenClicked = true, 500);
-    }
-
-    private handlePaste = action((e: React.ChangeEvent<HTMLInputElement>) => {
-        this.authenticationCode = e.currentTarget.value;
-    });
-
     private get renderPrompt() {
         return (
             <div className={'authorize-container'}>
                 {this.displayLauncher ? <button
                     className={"dispatch"}
-                    onClick={this.handleClick}
+                    onClick={() => {
+                        window.open(this.authenticationLink);
+                        setTimeout(() => this.hasBeenClicked = true, 500);
+                    }}
                     style={{ marginBottom: this.clickedState ? 15 : 0 }}
                 >Authorize a Google account...</button> : (null)}
                 {this.clickedState ? <input
                     className={'paste-target'}
-                    onChange={this.handlePaste}
+                    onChange={action(e => this.authenticationCode = e.currentTarget.value)}
                     placeholder={prompt}
                 /> : (null)}
                 {this.avatar ? <img
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 8167416c6..a0cb1fe19 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -27,7 +27,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
     protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view
         this._dropDisposer?.();
         if (ele) {
-            this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this));
+            this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this));
         }
     }
 
@@ -41,21 +41,21 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
     }
 
     panelHeight = () => this.props.PanelHeight() - 50;
-    @computed get content() { 
+    @computed get content() {
         const index = NumCast(this.layoutDoc._itemIndex);
         return !(this.childLayoutPairs?.[index]?.layout instanceof Doc) ? (null) :
-        <>
-            <div className="collectionCarouselView-image" key="image">
-                <ContentFittingDocumentView {...this.props}
-                    Document={this.childLayoutPairs[index].layout}
-                    DataDocument={this.childLayoutPairs[index].data}
-                    PanelHeight={this.panelHeight}
-                    getTransform={this.props.ScreenToLocalTransform} />
-            </div>
-            <div className="collectionCarouselView-caption" key="caption" style={{ background: this.props.backgroundColor?.(this.props.Document) }}>
-                <FormattedTextBox key={index} {...this.props} Document={this.childLayoutPairs[index].layout} DataDoc={undefined} fieldKey={"caption"}></FormattedTextBox>
-            </div>
-        </>
+            <>
+                <div className="collectionCarouselView-image" key="image">
+                    <ContentFittingDocumentView {...this.props}
+                        Document={this.childLayoutPairs[index].layout}
+                        DataDocument={this.childLayoutPairs[index].data}
+                        PanelHeight={this.panelHeight}
+                        getTransform={this.props.ScreenToLocalTransform} />
+                </div>
+                <div className="collectionCarouselView-caption" key="caption" style={{ background: this.props.backgroundColor?.(this.props.Document) }}>
+                    <FormattedTextBox key={index} {...this.props} Document={this.childLayoutPairs[index].layout} DataDoc={undefined} fieldKey={"caption"}></FormattedTextBox>
+                </div>
+            </>;
     }
     @computed get buttons() {
         return <>
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 7eb316cf0..9bbc9f1b6 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -67,7 +67,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
     protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view
         this._dropDisposer && this._dropDisposer();
         if (ele) {
-            this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this));
+            this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this));
         }
     }
 
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index e25a2f5eb..f3d512a97 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -80,7 +80,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
             const key = StrCast(this.props.parent.props.Document.sectionFilter);
             const castedValue = this.getValue(this._heading);
             de.complete.docDragData.droppedDocuments.forEach(d => d[key] = castedValue);
-            this.props.parent.drop(e, de);
+            this.props.parent.onInternalDrop(e, de);
             e.stopPropagation();
         }
     });
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index fa8be5177..c422c38f1 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -14,7 +14,6 @@ import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
 import { ComputedField } from "../../../new_fields/ScriptField";
 import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
 import { Docs, DocumentOptions } from "../../documents/Documents";
-import { DocumentType } from "../../documents/DocumentTypes";
 import { Gateway } from "../../northstar/manager/Gateway";
 import { CompileScript, Transformer, ts } from "../../util/Scripting";
 import { Transform } from "../../util/Transform";
@@ -175,7 +174,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
             moveDocument={this.props.moveDocument}
             ScreenToLocalTransform={this.props.ScreenToLocalTransform}
             active={this.props.active}
-            onDrop={this.onDrop}
+            onDrop={this.onExternalDrop}
             addDocTab={this.props.addDocTab}
             pinToPres={this.props.pinToPres}
             isSelected={this.props.isSelected}
@@ -199,7 +198,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
 
     render() {
         return <div className="collectionSchemaView-container">
-            <div className="collectionSchemaView-tableContainer" onPointerDown={this.onPointerDown} onWheel={e => this.props.active(true) && e.stopPropagation()} onDrop={e => this.onDrop(e, {})} ref={this.createTarget}>
+            <div className="collectionSchemaView-tableContainer" onPointerDown={this.onPointerDown} onWheel={e => this.props.active(true) && e.stopPropagation()} onDrop={e => this.onExternalDrop(e, {})} ref={this.createTarget}>
                 {this.schemaTable}
             </div>
             {this.dividerDragger}
@@ -692,7 +691,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     onContextMenu = (e: React.MouseEvent): void => {
         if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
             // ContextMenu.Instance.addItem({ description: "Make DB", event: this.makeDB, icon: "table" });
-            ContextMenu.Instance.addItem({ description: "Toggle text wrapping", event: this.toggleTextwrap, icon: "table" })
+            ContextMenu.Instance.addItem({ description: "Toggle text wrapping", event: this.toggleTextwrap, icon: "table" });
         }
     }
 
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 055035b3e..a9cefae6a 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -189,7 +189,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
     getDocHeight(d?: Doc) {
         if (!d) return 0;
-        let layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
+        const layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
         const nw = NumCast(layoutDoc._nativeWidth);
         const nh = NumCast(layoutDoc._nativeHeight);
         let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
@@ -234,7 +234,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
 
     @undoBatch
     @action
-    drop = (e: Event, de: DragManager.DropEvent) => {
+    onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
         const where = [de.x, de.y];
         let targInd = -1;
         let plusOne = 0;
@@ -248,7 +248,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                     plusOne = where[axis] > (pos[axis] + pos1[axis]) / 2 ? 1 : 0;
                 }
             });
-            if (super.drop(e, de)) {
+            if (super.onInternalDrop(e, de)) {
                 const newDoc = de.complete.docDragData.droppedDocuments[0];
                 const docs = this.childDocList;
                 if (docs) {
@@ -264,7 +264,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
     @undoBatch
     @action
-    onDrop = async (e: React.DragEvent): Promise<void> => {
+    onExternalDrop = async (e: React.DragEvent): Promise<void> => {
         const where = [e.clientX, e.clientY];
         let targInd = -1;
         this._docXfs.map((cd, i) => {
@@ -274,7 +274,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                 targInd = i;
             }
         });
-        super.onDrop(e, {}, () => {
+        super.onExternalDrop(e, {}, () => {
             if (targInd !== -1) {
                 const newDoc = this.childDocs[this.childDocs.length - 1];
                 const docs = this.childDocList;
@@ -405,7 +405,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                         transformOrigin: "top left",
                     }}
                     onScroll={action((e: React.UIEvent<HTMLDivElement>) => this._scroll = e.currentTarget.scrollTop)}
-                    onDrop={this.onDrop.bind(this)}
+                    onDrop={this.onExternalDrop.bind(this)}
                     onContextMenu={this.onContextMenu}
                     onWheel={e => this.props.active() && e.stopPropagation()} >
                     {this.renderedSections}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 2ff477c57..87c35679f 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -71,7 +71,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
             else {
                 de.complete.docDragData.droppedDocuments.forEach(d => d[key] = undefined);
             }
-            this.props.parent.drop(e, de);
+            this.props.parent.onInternalDrop(e, de);
             e.stopPropagation();
         }
     });
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index e80e1c802..042385dcd 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -57,7 +57,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
             this.gestureDisposer?.();
             this.multiTouchDisposer?.();
             if (ele) {
-                this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this));
+                this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this));
                 this.gestureDisposer = GestureUtils.MakeGestureTarget(ele, this.onGesture.bind(this));
                 this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(ele, this.onTouchStart.bind(this));
             }
@@ -156,7 +156,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
 
         @undoBatch
         @action
-        protected drop(e: Event, de: DragManager.DropEvent): boolean {
+        protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean {
             const docDragData = de.complete.docDragData;
             (this.props.Document.dropConverter instanceof ScriptField) &&
                 this.props.Document.dropConverter.script.run({ dragData: docDragData }); /// bcz: check this 
@@ -195,158 +195,172 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
 
         @undoBatch
         @action
-        protected async onDrop(e: React.DragEvent, options: DocumentOptions, completed?: () => void) {
+        protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions, completed?: () => void) {
             if (e.ctrlKey) {
                 e.stopPropagation(); // bcz: this is a hack to stop propagation when dropping an image on a text document with shift+ctrl
                 return;
             }
-            const html = e.dataTransfer.getData("text/html");
-            const text = e.dataTransfer.getData("text/plain");
+
+            const { dataTransfer } = e;
+            const html = dataTransfer.getData("text/html");
+            const text = dataTransfer.getData("text/plain");
 
             if (text && text.startsWith("<div")) {
                 return;
             }
+
             e.stopPropagation();
             e.preventDefault();
-
-            if (html && FormattedTextBox.IsFragment(html)) {
-                const href = FormattedTextBox.GetHref(html);
-                if (href) {
-                    const docid = FormattedTextBox.GetDocFromUrl(href);
-                    if (docid) { // prosemirror text containing link to dash document
-                        DocServer.GetRefField(docid).then(f => {
-                            if (f instanceof Doc) {
-                                if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView
-                                (f instanceof Doc) && this.props.addDocument(f);
-                            }
-                        });
-                    } else {
-                        this.props.addDocument && this.props.addDocument(Docs.Create.WebDocument(href, { ...options, title: href }));
-                    }
-                } else if (text) {
-                    this.props.addDocument && this.props.addDocument(Docs.Create.TextDocument(text, { ...options, _width: 100, _height: 25 }));
-                }
+            const { addDocument } = this.props;
+            if (!addDocument) {
+                alert("this.props.addDocument does not exist. Aborting drop operation.");
                 return;
             }
-            if (html && !html.startsWith("<a")) {
-                const tags = html.split("<");
-                if (tags[0] === "") tags.splice(0, 1);
-                const img = tags[0].startsWith("img") ? tags[0] : tags.length > 1 && tags[1].startsWith("img") ? tags[1] : "";
-                if (img) {
-                    const split = img.split("src=\"")[1].split("\"")[0];
-                    let source = split;
-                    if (split.startsWith("data:image") && split.includes("base64")) {
-                        const [{ accessPaths }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [split] });
-                        source = Utils.prepend(accessPaths.agnostic.client);
+
+            if (html) {
+                if (FormattedTextBox.IsFragment(html)) {
+                    const href = FormattedTextBox.GetHref(html);
+                    if (href) {
+                        const docid = FormattedTextBox.GetDocFromUrl(href);
+                        if (docid) { // prosemirror text containing link to dash document
+                            DocServer.GetRefField(docid).then(f => {
+                                if (f instanceof Doc) {
+                                    if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView
+                                    (f instanceof Doc) && addDocument(f);
+                                }
+                            });
+                        } else {
+                            addDocument(Docs.Create.WebDocument(href, { ...options, title: href }));
+                        }
+                    } else if (text) {
+                        addDocument(Docs.Create.TextDocument(text, { ...options, _width: 100, _height: 25 }));
                     }
-                    const doc = Docs.Create.ImageDocument(source, { ...options, _width: 300 });
-                    ImageUtils.ExtractExif(doc);
-                    this.props.addDocument(doc);
                     return;
-                } else {
-                    const path = window.location.origin + "/doc/";
-                    if (text.startsWith(path)) {
-                        const docid = text.replace(Utils.prepend("/doc/"), "").split("?")[0];
-                        DocServer.GetRefField(docid).then(f => {
-                            if (f instanceof Doc) {
-                                if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView
-                                (f instanceof Doc) && this.props.addDocument(f);
-                            }
-                        });
+                }
+                if (!html.startsWith("<a")) {
+                    const tags = html.split("<");
+                    if (tags[0] === "") tags.splice(0, 1);
+                    const img = tags[0].startsWith("img") ? tags[0] : tags.length > 1 && tags[1].startsWith("img") ? tags[1] : "";
+                    if (img) {
+                        const split = img.split("src=\"")[1].split("\"")[0];
+                        let source = split;
+                        if (split.startsWith("data:image") && split.includes("base64")) {
+                            const [{ accessPaths }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [split] });
+                            source = Utils.prepend(accessPaths.agnostic.client);
+                        }
+                        const doc = Docs.Create.ImageDocument(source, { ...options, _width: 300 });
+                        ImageUtils.ExtractExif(doc);
+                        addDocument(doc);
+                        return;
                     } else {
-                        const htmlDoc = Docs.Create.HtmlDocument(html, { ...options, title: "-web page-", _width: 300, _height: 300 });
-                        Doc.GetProto(htmlDoc)["data-text"] = text;
-                        this.props.addDocument(htmlDoc);
+                        const path = window.location.origin + "/doc/";
+                        if (text.startsWith(path)) {
+                            const docid = text.replace(Utils.prepend("/doc/"), "").split("?")[0];
+                            DocServer.GetRefField(docid).then(f => {
+                                if (f instanceof Doc) {
+                                    if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView
+                                    (f instanceof Doc) && this.props.addDocument(f);
+                                }
+                            });
+                        } else {
+                            const htmlDoc = Docs.Create.HtmlDocument(html, { ...options, title: "-web page-", _width: 300, _height: 300 });
+                            Doc.GetProto(htmlDoc)["data-text"] = text;
+                            this.props.addDocument(htmlDoc);
+                        }
+                        return;
                     }
-                    return;
                 }
             }
-            if (text && text.indexOf("www.youtube.com/watch") !== -1) {
-                const url = text.replace("youtube.com/watch?v=", "youtube.com/embed/");
-                this.props.addDocument(Docs.Create.VideoDocument(url, { ...options, title: url, _width: 400, _height: 315, _nativeWidth: 600, _nativeHeight: 472.5 }));
-                return;
-            }
-            let matches: RegExpExecArray | null;
-            if ((matches = /(https:\/\/)?docs\.google\.com\/document\/d\/([^\\]+)\/edit/g.exec(text)) !== null) {
-                const newBox = Docs.Create.TextDocument("", { ...options, _width: 400, _height: 200, title: "Awaiting title from Google Docs..." });
-                const proto = newBox.proto!;
-                const documentId = matches[2];
-                proto[GoogleRef] = documentId;
-                proto.data = "Please select this document and then click on its pull button to load its contents from from Google Docs...";
-                proto.backgroundColor = "#eeeeff";
-                this.props.addDocument(newBox);
-                // const parent = Docs.Create.StackingDocument([newBox], { title: `Google Doc Import (${documentId})` });
-                // CollectionDockingView.Instance.AddRightSplit(parent, undefined);
-                // proto.height = parent[HeightSym]();
-                return;
-            }
-            if ((matches = /(https:\/\/)?photos\.google\.com\/(u\/3\/)?album\/([^\\]+)/g.exec(text)) !== null) {
-                const albums = await GooglePhotos.Transactions.ListAlbums();
-                const albumId = matches[3];
-                const mediaItems = await GooglePhotos.Query.AlbumSearch(albumId);
-                console.log(mediaItems);
-                return;
+
+            if (text) {
+                if (text.includes("www.youtube.com/watch")) {
+                    const url = text.replace("youtube.com/watch?v=", "youtube.com/embed/");
+                    addDocument(Docs.Create.VideoDocument(url, {
+                        ...options,
+                        title: url,
+                        _width: 400,
+                        _height: 315,
+                        _nativeWidth: 600,
+                        _nativeHeight: 472.5
+                    }));
+                    return;
+                }
+                let matches: RegExpExecArray | null;
+                if ((matches = /(https:\/\/)?docs\.google\.com\/document\/d\/([^\\]+)\/edit/g.exec(text)) !== null) {
+                    const newBox = Docs.Create.TextDocument("", { ...options, _width: 400, _height: 200, title: "Awaiting title from Google Docs..." });
+                    const proto = newBox.proto!;
+                    const documentId = matches[2];
+                    proto[GoogleRef] = documentId;
+                    proto.data = "Please select this document and then click on its pull button to load its contents from from Google Docs...";
+                    proto.backgroundColor = "#eeeeff";
+                    addDocument(newBox);
+                    return;
+                }
+                if ((matches = /(https:\/\/)?photos\.google\.com\/(u\/3\/)?album\/([^\\]+)/g.exec(text)) !== null) {
+                    const albumId = matches[3];
+                    const mediaItems = await GooglePhotos.Query.AlbumSearch(albumId);
+                    console.log(mediaItems);
+                    return;
+                }
             }
+
             const { items } = e.dataTransfer;
             const { length } = items;
             const files: File[] = [];
-            if (length) {
-                const batch = UndoManager.StartBatch("collection view drop");
-                const promises: Promise<void>[] = [];
-                // tslint:disable-next-line:prefer-for-of
-                for (let i = 0; i < length; i++) {
-                    const item = e.dataTransfer.items[i];
-                    if (item.kind === "string" && item.type.indexOf("uri") !== -1) {
-                        let str: string;
-                        const prom = new Promise<string>(resolve => item.getAsString(resolve))
-                            .then(action((s: string) => rp.head(Utils.CorsProxy(str = s))))
-                            .then(result => {
-                                const type = result["content-type"];
-                                if (type) {
-                                    Docs.Get.DocumentFromType(type, str, options)
-                                        .then(doc => doc && this.props.addDocument(doc));
-                                }
-                            });
-                        promises.push(prom);
-                    }
-                    if (item.kind === "file") {
-                        const file = item.getAsFile();
-                        file && file.type && files.push(file);
+            const generatedDocuments: Doc[] = [];
+            if (!length) {
+                alert("No uploadable content found.");
+                return;
+            }
+
+            const batch = UndoManager.StartBatch("collection view drop");
+            for (let i = 0; i < length; i++) {
+                const item = e.dataTransfer.items[i];
+                if (item.kind === "string" && item.type.includes("uri")) {
+                    const stringContents = await new Promise<string>(resolve => item.getAsString(resolve));
+                    const type = (await rp.head(Utils.CorsProxy(stringContents)))["content-type"];
+                    if (type) {
+                        const doc = await Docs.Get.DocumentFromType(type, stringContents, options);
+                        doc && generatedDocuments.push(doc);
                     }
                 }
-                promises.push(Networking.UploadFilesToServer(files).then(responses => responses.forEach(({ source: { name, type }, result }) => {
-                    if (result instanceof Error) {
-                        alert(`Upload failed: ${result.message}`);
-                        return;
-                    }
-                    const full = { ...options, _width: 300, title: name };
-                    const pathname = Utils.prepend(result.accessPaths.agnostic.client);
-                    Docs.Get.DocumentFromType(type, pathname, full).then(doc => {
-                        if (doc) {
-                            const proto = Doc.GetProto(doc);
-                            proto.fileUpload = basename(pathname).replace("upload_", "").replace(/\.[a-z0-9]*$/, "");
-                            if (Upload.isImageInformation(result)) {
-                                proto["data-nativeWidth"] = result.nativeWidth;
-                                proto["data-nativeHeight"] = result.nativeHeight;
-                                proto.contentSize = result.contentSize;
-                            }
-                            this.props?.addDocument(doc);
-                        }
-                    });
-                })));
-                if (promises.length) {
-                    Promise.all(promises).finally(() => { completed && completed(); batch.end(); });
-                } else {
-                    if (text && !text.includes("https://")) {
-                        this.props.addDocument(Docs.Create.TextDocument(text, { ...options, _width: 400, _height: 315 }));
-                    }
-                    batch.end();
+                if (item.kind === "file") {
+                    const file = item.getAsFile();
+                    file && file.type && files.push(file);
+                }
+            }
+            for (const { source: { name, type }, result } of await Networking.UploadFilesToServer(files)) {
+                if (result instanceof Error) {
+                    alert(`Upload failed: ${result.message}`);
+                    return;
                 }
+                const full = { ...options, _width: 300, title: name };
+                const pathname = Utils.prepend(result.accessPaths.agnostic.client);
+                const doc = await Docs.Get.DocumentFromType(type, pathname, full);
+                if (!doc) {
+                    continue;
+                }
+                const proto = Doc.GetProto(doc);
+                proto.fileUpload = basename(pathname).replace("upload_", "").replace(/\.[a-z0-9]*$/, "");
+                if (Upload.isImageInformation(result)) {
+                    proto["data-nativeWidth"] = result.nativeWidth;
+                    proto["data-nativeHeight"] = result.nativeHeight;
+                    proto.contentSize = result.contentSize;
+                }
+                generatedDocuments.push(doc);
+            }
+            if (generatedDocuments.length) {
+                generatedDocuments.forEach(addDocument);
+                completed && completed();
             } else {
-                alert("No uploadable content found.");
+                if (text && !text.includes("https://")) {
+                    addDocument(Docs.Create.TextDocument(text, { ...options, _width: 400, _height: 315 }));
+                }
             }
+            batch.end();
         }
     }
+
     return CollectionSubView;
 }
 
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 8720ce002..13ab7c1a4 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -210,7 +210,7 @@ class TreeView extends React.Component<TreeViewProps> {
             } else {
                 ContextMenu.Instance.addItem({ description: "Delete Workspace", event: () => this.props.deleteDoc(this.props.document), icon: "trash-alt" });
                 ContextMenu.Instance.addItem({ description: "Create New Workspace", event: () => MainView.Instance.createNewWorkspace(), icon: "plus" });
-            }    
+            }
             ContextMenu.Instance.addItem({ description: "Toggle Theme Colors", event: () => this.props.document.darkScheme = !this.props.document.darkScheme, icon: "minus" });
             ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { const kvp = Docs.Create.KVPDocument(this.props.document, { _width: 300, _height: 300 }); this.props.addDocTab(kvp, this.props.dataDoc ? this.props.dataDoc : kvp, "onRight"); }, icon: "layer-group" });
             ContextMenu.Instance.addItem({ description: "Publish", event: () => DocUtils.Publish(this.props.document, StrCast(this.props.document.title), () => { }, () => { }), icon: "file" });
@@ -594,7 +594,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
     protected createTreeDropTarget = (ele: HTMLDivElement) => {
         this.treedropDisposer && this.treedropDisposer();
         if (this._mainEle = ele) {
-            this.treedropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this));
+            this.treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this));
         }
     }
 
@@ -702,7 +702,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
         !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" });
     }
     outerXf = () => Utils.GetScreenTransform(this._mainEle!);
-    onTreeDrop = (e: React.DragEvent) => this.onDrop(e, {});
+    onTreeDrop = (e: React.DragEvent) => this.onExternalDrop(e, {});
 
     @computed get renderClearButton() {
         return <div id="toolbar" key="toolbar">
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 969d6b3c8..bdc5e03e3 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -117,20 +117,20 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     }
 
     @action
-    onDrop = (e: React.DragEvent): Promise<void> => {
+    onExternalDrop = (e: React.DragEvent): Promise<void> => {
         const pt = this.getTransform().transformPoint(e.pageX, e.pageY);
-        return super.onDrop(e, { x: pt[0], y: pt[1] });
+        return super.onExternalDrop(e, { x: pt[0], y: pt[1] });
     }
 
     @undoBatch
     @action
-    drop = (e: Event, de: DragManager.DropEvent) => {
+    onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
         if (this.props.Document.isBackground) return false;
         const xf = this.getTransform();
         const xfo = this.getTransformOverlay();
         const [xp, yp] = xf.transformPoint(de.x, de.y);
         const [xpo, ypo] = xfo.transformPoint(de.x, de.y);
-        if (super.drop(e, de)) {
+        if (super.onInternalDrop(e, de)) {
             if (de.complete.docDragData) {
                 if (de.complete.docDragData.droppedDocuments.length) {
                     const firstDoc = de.complete.docDragData.droppedDocuments[0];
@@ -1079,7 +1079,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         return <div className={"collectionfreeformview-container"}
             ref={this.createDashEventsTarget}
             onWheel={this.onPointerWheel}//pointerEvents: SelectionManager.GetIsDragging() ? "all" : undefined,
-            onPointerDown={this.onPointerDown} onPointerMove={this.onCursorMove} onDrop={this.onDrop.bind(this)} onContextMenu={this.onContextMenu}
+            onPointerDown={this.onPointerDown} onPointerMove={this.onCursorMove} onDrop={this.onExternalDrop.bind(this)} onContextMenu={this.onContextMenu}
             style={{
                 pointerEvents: SelectionManager.GetIsDragging() ? "all" : undefined,
                 transform: this.contentScaling ? `scale(${this.contentScaling})` : "",
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index db5673573..785f90212 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -189,8 +189,8 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
 
     @undoBatch
     @action
-    drop = (e: Event, de: DragManager.DropEvent) => {
-        if (super.drop(e, de)) {
+    onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
+        if (super.onInternalDrop(e, de)) {
             de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => {
                 d.dimUnit = "*";
                 d.dimMagnitude = 1;
@@ -214,7 +214,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
             getTransform={dxf}
             onClick={this.onChildClickHandler}
             renderDepth={this.props.renderDepth + 1}
-        />
+        />;
     }
     /**
      * @returns the resolved list of rendered child documents, displayed
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 630a178cf..5e59f8237 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -190,8 +190,8 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
 
     @undoBatch
     @action
-    drop = (e: Event, de: DragManager.DropEvent) => {
-        if (super.drop(e, de)) {
+    onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
+        if (super.onInternalDrop(e, de)) {
             de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => {
                 d.dimUnit = "*";
                 d.dimMagnitude = 1;
@@ -215,7 +215,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
             getTransform={dxf}
             onClick={this.onChildClickHandler}
             renderDepth={this.props.renderDepth + 1}
-        />
+        />;
     }
     /**
      * @returns the resolved list of rendered child documents, displayed
diff --git a/src/server/ApiManagers/DeleteManager.ts b/src/server/ApiManagers/DeleteManager.ts
index be452c0ff..9e70af2eb 100644
--- a/src/server/ApiManagers/DeleteManager.ts
+++ b/src/server/ApiManagers/DeleteManager.ts
@@ -2,6 +2,11 @@ import ApiManager, { Registration } from "./ApiManager";
 import { Method, _permission_denied, PublicHandler } from "../RouteManager";
 import { WebSocket } from "../Websocket/Websocket";
 import { Database } from "../database";
+import rimraf = require("rimraf");
+import { pathToDirectory, Directory } from "./UploadManager";
+import { filesDirectory } from "..";
+import { DashUploadUtils } from "../DashUploadUtils";
+import { mkdirSync } from "fs";
 
 export default class DeleteManager extends ApiManager {
 
@@ -31,21 +36,19 @@ export default class DeleteManager extends ApiManager {
             }
         });
 
-        const hi: PublicHandler = async ({ res, isRelease }) => {
-            if (isRelease) {
-                return _permission_denied(res, deletionPermissionError);
+        register({
+            method: Method.GET,
+            subscription: "/deleteAssets",
+            secureHandler: async ({ res, isRelease }) => {
+                if (isRelease) {
+                    return _permission_denied(res, deletionPermissionError);
+                }
+                rimraf.sync(filesDirectory);
+                mkdirSync(filesDirectory);
+                await DashUploadUtils.buildFileDirectories();
+                res.redirect("/delete");
             }
-            await Database.Instance.deleteAll('users');
-            res.redirect("/home");
-        };
-
-        // register({
-        //     method: Method.GET,
-        //     subscription: "/deleteUsers",
-        //     onValidation: hi,
-        //     onUnauthenticated: hi
-        // });
-
+        });
 
         register({
             method: Method.GET,
-- 
cgit v1.2.3-70-g09d2


From 2ae91501a3195da9dcbc02e180b108983cd1d8af Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 16 Feb 2020 21:47:28 -0500
Subject: got rid of unneeded ignoreAspect field.   other cleanup.

---
 src/client/util/RichTextSchema.tsx                      |  2 +-
 src/client/views/DocumentDecorations.tsx                |  9 ++-------
 src/client/views/collections/CollectionDockingView.tsx  |  8 ++++----
 .../views/collections/CollectionMasonryViewFieldRow.tsx |  3 ++-
 src/client/views/collections/CollectionStackingView.tsx |  6 +++---
 src/client/views/collections/CollectionView.tsx         | 17 -----------------
 .../views/nodes/CollectionFreeFormDocumentView.tsx      |  2 +-
 src/client/views/nodes/DocumentView.tsx                 | 15 +++++----------
 src/client/views/nodes/ImageBox.tsx                     |  2 +-
 src/client/views/nodes/PDFBox.tsx                       |  4 ++--
 src/new_fields/Doc.ts                                   |  3 +--
 src/new_fields/documentSchemas.ts                       |  1 -
 12 files changed, 22 insertions(+), 50 deletions(-)

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

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 3a3bcd1ad..656215368 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -723,7 +723,7 @@ export class DashDocView {
         const { scale, translateX, translateY } = Utils.GetScreenTransform(this._outer);
         return new Transform(-translateX, -translateY, 1).scale(1 / this.contentScaling() / scale);
     }
-    contentScaling = () => NumCast(this._dashDoc!._nativeWidth) > 0 && !this._dashDoc!.ignoreAspect ? this._dashDoc![WidthSym]() / NumCast(this._dashDoc!._nativeWidth) : 1;
+    contentScaling = () => NumCast(this._dashDoc!._nativeWidth) > 0 ? this._dashDoc![WidthSym]() / NumCast(this._dashDoc!._nativeWidth) : 1;
     outerFocus = (target: Doc) => this._textBox.props.focus(this._textBox.props.Document);  // ideally, this would scroll to show the focus target
     constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) {
         this._textBox = tbox;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 5fc14e716..cc7388a61 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -283,17 +283,12 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 const actualdH = Math.max(height + (dH * scale), 20);
                 doc.x = (doc.x || 0) + dX * (actualdW - width);
                 doc.y = (doc.y || 0) + dY * (actualdH - height);
-                const fixedAspect = e.ctrlKey || (!layoutDoc.ignoreAspect && nwidth && nheight);
-                if (fixedAspect && e.ctrlKey && layoutDoc.ignoreAspect) {
-                    layoutDoc.ignoreAspect = false;
-                    layoutDoc._nativeWidth = nwidth = layoutDoc._width || 0;
-                    layoutDoc._nativeHeight = nheight = layoutDoc._height || 0;
-                }
+                const fixedAspect = e.ctrlKey || (nwidth && nheight);
                 if (fixedAspect && (!nwidth || !nheight)) {
                     layoutDoc._nativeWidth = nwidth = layoutDoc._width || 0;
                     layoutDoc._nativeHeight = nheight = layoutDoc._height || 0;
                 }
-                if (nwidth > 0 && nheight > 0 && !layoutDoc.ignoreAspect) {
+                if (nwidth > 0 && nheight > 0) {
                     if (Math.abs(dW) > Math.abs(dH)) {
                         if (!fixedAspect) {
                             layoutDoc._nativeWidth = actualdW / (layoutDoc._width || 1) * (layoutDoc._nativeWidth || 0);
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 6abfb59c3..bf0333d55 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -678,8 +678,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     panelWidth = () => this.layoutDoc && this.layoutDoc.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._nativeWidth)), this._panelWidth) : this._panelWidth;
     panelHeight = () => this._panelHeight;
 
-    nativeWidth = () => !this.layoutDoc!.ignoreAspect && !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeWidth) || this._panelWidth : 0;
-    nativeHeight = () => !this.layoutDoc!.ignoreAspect && !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeHeight) || this._panelHeight : 0;
+    nativeWidth = () => !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeWidth) || this._panelWidth : 0;
+    nativeHeight = () => !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeHeight) || this._panelHeight : 0;
 
     contentScaling = () => {
         if (this.layoutDoc!.type === DocumentType.PDF) {
@@ -705,8 +705,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
         }
         return Transform.Identity();
     }
-    get previewPanelCenteringOffset() { return this.nativeWidth() && !this.layoutDoc!.ignoreAspect ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
-    get widthpercent() { return this.nativeWidth() && !this.layoutDoc!.ignoreAspect ? `${(this.nativeWidth() * this.contentScaling()) / this.panelWidth() * 100}%` : undefined; }
+    get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
+    get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this.panelWidth() * 100}%` : undefined; }
 
     addDocTab = (doc: Doc, dataDoc: Opt<Doc>, location: string, libraryPath?: Doc[]) => {
         SelectionManager.DeselectAll();
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index f3dd7c733..c9b7ca221 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -259,7 +259,8 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
 
     @computed get contentLayout() {
         const rows = Math.max(1, Math.min(this.props.docList.length, Math.floor((this.props.parent.props.PanelWidth() - 2 * this.props.parent.xMargin) / (this.props.parent.columnWidth + this.props.parent.gridGap))));
-        const style = this.props.parent; const collapsed = this._collapsed;
+        const style = this.props.parent;
+        const collapsed = this._collapsed;
         const chromeStatus = this.props.parent.props.Document._chromeStatus;
         const newEditableViewProps = {
             GetValue: () => "",
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index a9cefae6a..ad9dc8f7c 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -185,7 +185,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         if (!d) return 0;
         const layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
         const nw = NumCast(layoutDoc._nativeWidth);
-        return Math.min(nw && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns);
+        return Math.min(nw && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns);
     }
     getDocHeight(d?: Doc) {
         if (!d) return 0;
@@ -193,9 +193,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         const nw = NumCast(layoutDoc._nativeWidth);
         const nh = NumCast(layoutDoc._nativeHeight);
         let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
-        if (!layoutDoc.ignoreAspect && !layoutDoc._fitWidth && nw && nh) {
+        if (!layoutDoc._fitWidth && nw && nh) {
             const aspect = nw && nh ? nh / nw : 1;
-            if (!(!layoutDoc.ignoreAspect && this.props.Document.fillColumn)) wid = Math.min(layoutDoc[WidthSym](), wid);
+            if (!(this.props.Document.fillColumn)) wid = Math.min(layoutDoc[WidthSym](), wid);
             return wid * aspect;
         }
         return layoutDoc._fitWidth ? !nh ? this.props.PanelHeight() - 2 * this.yMargin :
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 48294f9c2..52a18fb99 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -90,11 +90,9 @@ export interface CollectionRenderProps {
 export class CollectionView extends Touchable<FieldViewProps> {
     public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); }
 
-    private _reactionDisposer: IReactionDisposer | undefined;
     private _isChildActive = false;   //TODO should this be observable?
     @observable private _isLightboxOpen = false;
     @observable private _curLightboxImg = 0;
-    @observable private _collapsed = true;
     @observable private static _safeMode = false;
     public static SetSafeMode(safeMode: boolean) { this._safeMode = safeMode; }
 
@@ -111,20 +109,6 @@ export class CollectionView extends Touchable<FieldViewProps> {
         return viewField;
     }
 
-    componentDidMount = () => {
-        this._reactionDisposer = reaction(() => StrCast(this.props.Document._chromeStatus),
-            () => {
-                // chrome status is one of disabled, collapsed, or visible. this determines initial state from document
-                // chrome status may also be view-mode, in reference to stacking view's toggle mode. it is essentially disabled mode, but prevents the toggle button from showing up on the left sidebar.
-                const chromeStatus = this.props.Document._chromeStatus;
-                if (chromeStatus && (chromeStatus === "disabled" || chromeStatus === "collapsed" || chromeStatus === "replaced")) {
-                    runInAction(() => this._collapsed = true);
-                }
-            });
-    }
-
-    componentWillUnmount = () => this._reactionDisposer && this._reactionDisposer();
-
     // bcz: Argh?  What's the height of the collection chromes??  
     chromeHeight = () => (this.props.Document._chromeStatus === "enabled" ? -60 : 0);
 
@@ -198,7 +182,6 @@ export class CollectionView extends Touchable<FieldViewProps> {
 
     @action
     private collapse = (value: boolean) => {
-        this._collapsed = value;
         this.props.Document._chromeStatus = value ? "collapsed" : "enabled";
     }
 
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 53d17b580..eaab4086c 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -60,7 +60,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
         return undefined;
     }
 
-    contentScaling = () => this.nativeWidth > 0 && !this.props.Document.ignoreAspect && !this.props.fitToBox ? this.width / this.nativeWidth : 1;
+    contentScaling = () => this.nativeWidth > 0 && !this.props.fitToBox ? this.width / this.nativeWidth : 1;
     panelWidth = () => (this.dataProvider?.width || this.props.PanelWidth());
     panelHeight = () => (this.dataProvider?.height || this.props.PanelHeight());
     getTransform = (): Transform => this.props.ScreenToLocalTransform()
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b4ec09aee..330410a92 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -364,18 +364,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 const actualdH = Math.max(height + (dH * scale), 20);
                 doc.x = (doc.x || 0) + dX * (actualdW - width);
                 doc.y = (doc.y || 0) + dY * (actualdH - height);
-                const fixedAspect = e.ctrlKey || (!layoutDoc.ignoreAspect && nwidth && nheight);
-                if (fixedAspect && e.ctrlKey && layoutDoc.ignoreAspect) {
-                    layoutDoc.ignoreAspect = false;
-
-                    layoutDoc._nativeWidth = nwidth = layoutDoc._width || 0;
-                    layoutDoc._nativeHeight = nheight = layoutDoc._height || 0;
-                }
+                const fixedAspect = e.ctrlKey || (nwidth && nheight);
                 if (fixedAspect && (!nwidth || !nheight)) {
                     layoutDoc._nativeWidth = nwidth = layoutDoc._width || 0;
                     layoutDoc._nativeHeight = nheight = layoutDoc._height || 0;
                 }
-                if (nwidth > 0 && nheight > 0 && !layoutDoc.ignoreAspect) {
+                if (nwidth > 0 && nheight > 0) {
                     if (Math.abs(dW) > Math.abs(dH)) {
                         if (!fixedAspect) {
                             layoutDoc._nativeWidth = actualdW / (layoutDoc._width || 1) * (layoutDoc._nativeWidth || 0);
@@ -546,10 +540,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     @undoBatch
-    public static unfreezeNativeDimensions = action((layoutDoc: Doc): void => {
+    @action
+    public static unfreezeNativeDimensions(layoutDoc: Doc) {
         layoutDoc._nativeWidth = undefined;
         layoutDoc._nativeHeight = undefined;
-    });
+    }
 
     toggleNativeDimensions = () => {
         if (this.Document._nativeWidth || this.Document._nativeHeight) {
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 364bce7a8..5b5768d54 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -375,7 +375,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
         const aspect = (rotation % 180) ? this.Document[HeightSym]() / this.Document[WidthSym]() : 1;
         const shift = (rotation % 180) ? (nativeHeight - nativeWidth / aspect) / 2 : 0;
 
-        !this.Document.ignoreAspect && this.resize(srcpath);
+        this.resize(srcpath);
 
         return <div className="imageBox-cont" key={this.props.Document[Id]} ref={this.createDropTarget} onContextMenu={this.specificContextMenu}>
             <div className="imageBox-fader" >
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index e1c5fd27f..a2aec699f 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -52,7 +52,7 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
         this._initialScale = this.props.ScreenToLocalTransform().Scale;
         const nw = this.Document._nativeWidth = NumCast(this.dataDoc[this.props.fieldKey + "-nativeWidth"], NumCast(this.Document._nativeWidth, 927));
         const nh = this.Document._nativeHeight = NumCast(this.dataDoc[this.props.fieldKey + "-nativeHeight"], NumCast(this.Document._nativeHeight, 1200));
-        !this.Document._fitWidth && !this.Document.ignoreAspect && (this.Document._height = this.Document[WidthSym]() * (nh / nw));
+        !this.Document._fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw));
 
         const backup = "oldPath";
         const { Document } = this.props;
@@ -93,7 +93,7 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
         this.dataDoc[this.props.fieldKey + "-numPages"] = np;
         this.dataDoc[this.props.fieldKey + "-nativeWidth"] = this.Document._nativeWidth = nw * 96 / 72;
         this.dataDoc[this.props.fieldKey + "-nativeHeight"] = this.Document._nativeHeight = nh * 96 / 72;
-        !this.Document._fitWidth && !this.Document.ignoreAspect && (this.Document._height = this.Document[WidthSym]() * (nh / nw));
+        !this.Document._fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw));
     }
 
     public search(string: string, fwd: boolean) { this._pdfViewer && this._pdfViewer.search(string, fwd); }
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index a722f552e..48890ac8d 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -840,8 +840,7 @@ export namespace Doc {
 
     export function freezeNativeDimensions(layoutDoc: Doc, width: number, height: number): void {
         layoutDoc._autoHeight = false;
-        layoutDoc.ignoreAspect = false;
-        if (!layoutDoc.ignoreAspect && !layoutDoc._nativeWidth) {
+        if (!layoutDoc._nativeWidth) {
             layoutDoc._nativeWidth = NumCast(layoutDoc._width, width);
             layoutDoc._nativeHeight = NumCast(layoutDoc._height, height);
         }
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index 3cc05d3d5..f3726cb5a 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -34,7 +34,6 @@ export const documentSchema = createSchema({
     onDragStart: ScriptField,   // script to run when document is dragged (without being selected).  the script should return the Doc to be dropped.
     dragFactory: Doc,           // the document that serves as the "template" for the onDragStart script.  ie, to drag out copies of the dragFactory document.
     removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped
-    ignoreAspect: "boolean",    // whether aspect ratio should be ignored when laying out or manipulating the document
     isTemplateForField: "string",// when specifies a field key, then the containing document is a template that renders the specified field
     isBackground: "boolean",    // whether document is a background element and ignores input events (can only selet with marquee)
     treeViewOpen: "boolean",    //  flag denoting whether the documents sub-tree (contents) is visible or hidden
-- 
cgit v1.2.3-70-g09d2


From d53ae2d90e7d7de8135ff19e18535cccd7a90ed0 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 19 Feb 2020 00:45:23 -0500
Subject: getting rid of data docs from many places

---
 src/client/documents/Documents.ts                  |  2 +-
 src/client/util/DictationManager.ts                |  4 +-
 src/client/util/DocumentManager.ts                 |  6 +--
 src/client/util/RichTextSchema.tsx                 |  2 +-
 src/client/views/DocComponent.tsx                  |  4 +-
 src/client/views/DocumentButtonBar.tsx             |  8 +--
 src/client/views/GlobalKeyHandler.ts               |  2 +-
 src/client/views/MainView.tsx                      |  6 +--
 src/client/views/MainViewNotifs.tsx                |  2 +-
 .../views/collections/CollectionDockingView.tsx    | 60 +++++++++-------------
 .../views/collections/CollectionSchemaCells.tsx    |  2 +-
 .../views/collections/CollectionSchemaView.tsx     |  2 +-
 .../views/collections/CollectionStackingView.tsx   |  6 +--
 .../views/collections/CollectionTreeView.tsx       | 12 ++---
 src/client/views/collections/CollectionView.tsx    |  4 +-
 .../views/collections/ParentDocumentSelector.tsx   |  4 +-
 src/client/views/linking/LinkFollowBox.tsx         | 16 +++---
 src/client/views/linking/LinkMenu.tsx              |  2 +-
 src/client/views/linking/LinkMenuGroup.tsx         |  2 +-
 src/client/views/linking/LinkMenuItem.tsx          |  2 +-
 .../views/nodes/ContentFittingDocumentView.tsx     |  2 +-
 src/client/views/nodes/DocuLinkBox.tsx             |  2 +-
 src/client/views/nodes/DocumentContentsView.tsx    |  2 +-
 src/client/views/nodes/DocumentView.tsx            | 22 ++++----
 src/client/views/nodes/FieldView.tsx               |  2 +-
 src/client/views/nodes/FontIconBox.tsx             |  2 +-
 src/client/views/nodes/FormattedTextBox.tsx        |  2 +-
 src/client/views/nodes/FormattedTextBoxComment.tsx |  4 +-
 src/client/views/nodes/KeyValuePair.tsx            |  4 +-
 src/client/views/nodes/PresBox.tsx                 |  4 +-
 src/client/views/nodes/VideoBox.tsx                |  2 +-
 src/client/views/pdf/Annotation.tsx                |  6 +--
 src/client/views/pdf/PDFViewer.tsx                 |  2 +-
 .../views/presentationview/PresElementBox.tsx      |  3 +-
 src/client/views/search/SearchItem.tsx             |  6 +--
 src/new_fields/Doc.ts                              |  4 +-
 36 files changed, 105 insertions(+), 112 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 669aa97b5..650538e93 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -654,7 +654,7 @@ export namespace Docs {
                     {
                         type: type,
                         content: [
-                            ...configs.map(config => CollectionDockingView.makeDocumentConfig(config.doc, undefined, config.initialWidth, config.path))
+                            ...configs.map(config => CollectionDockingView.makeDocumentConfig(config.doc, config.initialWidth, config.path))
                         ]
                     }
                 ]
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index 3394cb93d..569c1ef6d 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -326,7 +326,7 @@ export namespace DictationManager {
             ["open fields", {
                 action: (target: DocumentView) => {
                     const kvp = Docs.Create.KVPDocument(target.props.Document, { _width: 300, _height: 300 });
-                    target.props.addDocTab(kvp, target.props.DataDoc, "onRight");
+                    target.props.addDocTab(kvp, "onRight");
                 }
             }],
 
@@ -340,7 +340,7 @@ export namespace DictationManager {
                     const proseMirrorState = `{"doc":{"type":"doc","content":[{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","text":"${prompt}"}]}]}]}]},"selection":{"type":"text","anchor":${anchor},"head":${head}}}`;
                     proto.data = new RichTextField(proseMirrorState);
                     proto.backgroundColor = "#eeffff";
-                    target.props.addDocTab(newBox, proto, "onRight");
+                    target.props.addDocTab(newBox, "onRight");
                 }
             }]
 
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index bfda8e75b..c639f07f5 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -148,7 +148,7 @@ export class DocumentManager {
             const targetDocContext = (annotatedDoc ? annotatedDoc : contextDoc);
 
             if (!targetDocContext) { // we don't have a view and there's no context specified ... create a new view of the target using the dockFunc or default
-                (dockFunc || CollectionDockingView.AddRightSplit)(Doc.BrushDoc(Doc.MakeAlias(targetDoc)), undefined);
+                (dockFunc || CollectionDockingView.AddRightSplit)(Doc.BrushDoc(Doc.MakeAlias(targetDoc)));
                 highlight();
             } else {
                 const targetDocContextView = DocumentManager.Instance.getFirstDocumentView(targetDocContext);
@@ -164,12 +164,12 @@ export class DocumentManager {
                             retryDocView.props.focus(targetDoc, willZoom); // focus on the target if it now exists in the context
                         } else {
                             if (closeContextIfNotFound && targetDocContextView.props.removeDocument) targetDocContextView.props.removeDocument(targetDocContextView.props.Document);
-                            targetDoc.layout && (dockFunc || CollectionDockingView.AddRightSplit)(Doc.BrushDoc(Doc.MakeAlias(targetDoc)), undefined); // otherwise create a new view of the target
+                            targetDoc.layout && (dockFunc || CollectionDockingView.AddRightSplit)(Doc.BrushDoc(Doc.MakeAlias(targetDoc))); // otherwise create a new view of the target
                         }
                         highlight();
                     }, 0);
                 } else {  // there's no context view so we need to create one first and try again
-                    (dockFunc || CollectionDockingView.AddRightSplit)(targetDocContext, undefined);
+                    (dockFunc || CollectionDockingView.AddRightSplit)(targetDocContext);
                     setTimeout(() => {
                         const finalDocView = DocumentManager.Instance.getFirstDocumentView(targetDoc);
                         const finalDocContextView = DocumentManager.Instance.getFirstDocumentView(targetDocContext);
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 23b0a56a8..cfbae5dca 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -613,7 +613,7 @@ export class ImageResizeView {
                 DocServer.GetRefField(node.attrs.docid).then(async linkDoc =>
                     (linkDoc instanceof Doc) &&
                     DocumentManager.Instance.FollowLink(linkDoc, view.state.schema.Document,
-                        document => addDocTab(document, undefined, node.attrs.location ? node.attrs.location : "inTab"), false));
+                        document => addDocTab(document, node.attrs.location ? node.attrs.location : "inTab"), false));
             }
         };
         this._handle.onpointerdown = function (e: any) {
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 0bf944f22..61b1f9e0f 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -1,4 +1,4 @@
-import { Doc, Opt } from '../../new_fields/Doc';
+import { Doc, Opt, DataSym } from '../../new_fields/Doc';
 import { Touchable } from './Touchable';
 import { computed, action, observable } from 'mobx';
 import { Cast } from '../../new_fields/Types';
@@ -58,7 +58,7 @@ export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schema
         //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
         @computed get Document(): T { return schemaCtor(this.props.Document); }
         @computed get layoutDoc() { return Doc.Layout(this.props.Document); }
-        @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Cast(this.props.Document.resolvedDataDoc, Doc, null) || Doc.GetProto(this.props.Document)) as Doc; }
+        @computed get dataDoc() { return this.props.Document[DataSym]; }
 
         _annotationKey: string = "annotations";
         public set annotationKey(val: string) { this._annotationKey = val; }
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index b530d8a42..c8ad78f47 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -251,10 +251,10 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
 
     @computed
     get contextButton() {
-        return !this.view0 ? (null) : <ParentDocSelector Views={this.props.views.filter(v => v).map(v => v as DocumentView)} Document={this.view0.props.Document} addDocTab={(doc, data, where) => {
-            where === "onRight" ? CollectionDockingView.AddRightSplit(doc, data) :
-                this.props.stack ? CollectionDockingView.Instance.AddTab(this.props.stack, doc, data) :
-                    this.view0?.props.addDocTab(doc, data, "onRight");
+        return !this.view0 ? (null) : <ParentDocSelector Views={this.props.views.filter(v => v).map(v => v as DocumentView)} Document={this.view0.props.Document} addDocTab={(doc, where) => {
+            where === "onRight" ? CollectionDockingView.AddRightSplit(doc) :
+                this.props.stack ? CollectionDockingView.Instance.AddTab(this.props.stack, doc) :
+                    this.view0?.props.addDocTab(doc, "onRight");
             return true;
         }} />;
     }
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 979687ffb..d0900251d 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -156,7 +156,7 @@ export default class KeyManager {
                         return { stopPropagation: false, preventDefault: false };
                     }
                 }
-                MainView.Instance.mainFreeform && CollectionDockingView.AddRightSplit(MainView.Instance.mainFreeform, undefined);
+                MainView.Instance.mainFreeform && CollectionDockingView.AddRightSplit(MainView.Instance.mainFreeform);
                 break;
             case "arrowleft":
                 if (document.activeElement) {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 7948da3c5..1849ec250 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -185,7 +185,7 @@ export class MainView extends React.Component {
                 reaction(() => CollectionDockingView.Instance && CollectionDockingView.Instance.initialized,
                     initialized => initialized && received && DocServer.GetRefField(received).then(docField => {
                         if (docField instanceof Doc && docField._viewType !== CollectionViewType.Docking) {
-                            CollectionDockingView.AddRightSplit(docField, undefined);
+                            CollectionDockingView.AddRightSplit(docField);
                         }
                     }),
                 );
@@ -379,10 +379,10 @@ export class MainView extends React.Component {
         document.removeEventListener("pointerup", this.onPointerUp);
     }
     flyoutWidthFunc = () => this.flyoutWidth;
-    addDocTabFunc = (doc: Doc, data: Opt<Doc>, where: string, libraryPath?: Doc[]): boolean => {
+    addDocTabFunc = (doc: Doc, where: string, libraryPath?: Doc[]): boolean => {
         return where === "close" ? CollectionDockingView.CloseRightSplit(doc) :
             doc.dockingConfig ? this.openWorkspace(doc) :
-                CollectionDockingView.AddRightSplit(doc, undefined, libraryPath);
+                CollectionDockingView.AddRightSplit(doc, libraryPath);
     }
     mainContainerXf = () => new Transform(0, -this._buttonBarHeight, 1);
 
diff --git a/src/client/views/MainViewNotifs.tsx b/src/client/views/MainViewNotifs.tsx
index 09fa1cb0c..82e07c449 100644
--- a/src/client/views/MainViewNotifs.tsx
+++ b/src/client/views/MainViewNotifs.tsx
@@ -15,7 +15,7 @@ export class MainViewNotifs extends React.Component {
     @observable static NotifsCol: Opt<Doc>;
     openNotifsCol = () => {
         if (MainViewNotifs.NotifsCol) {
-            CollectionDockingView.AddRightSplit(MainViewNotifs.NotifsCol, undefined);
+            CollectionDockingView.AddRightSplit(MainViewNotifs.NotifsCol);
         }
     }
     render() {
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 26b65c898..6e1d522fc 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -8,7 +8,7 @@ import * as ReactDOM from 'react-dom';
 import Measure from "react-measure";
 import * as GoldenLayout from "../../../client/goldenLayout";
 import { DateField } from '../../../new_fields/DateField';
-import { Doc, DocListCast, Field, Opt } from "../../../new_fields/Doc";
+import { Doc, DocListCast, Field, Opt, DataSym } from "../../../new_fields/Doc";
 import { Id } from '../../../new_fields/FieldSymbols';
 import { List } from '../../../new_fields/List';
 import { FieldId } from "../../../new_fields/RefField";
@@ -38,7 +38,7 @@ const _global = (window /* browser */ || global /* node */) as any;
 export class CollectionDockingView extends React.Component<SubCollectionViewProps> {
     @observable public static Instances: CollectionDockingView[] = [];
     @computed public static get Instance() { return CollectionDockingView.Instances[0]; }
-    public static makeDocumentConfig(document: Doc, dataDoc: Doc | undefined, width?: number, libraryPath?: Doc[]) {
+    public static makeDocumentConfig(document: Doc, width?: number, libraryPath?: Doc[]) {
         return {
             type: 'react-component',
             component: 'DocumentFrameRenderer',
@@ -46,8 +46,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
             width: width,
             props: {
                 documentId: document[Id],
-                dataDocumentId: dataDoc && dataDoc[Id] !== document[Id] ? dataDoc[Id] : "",
-                libraryPath: libraryPath ? libraryPath.map(d => d[Id]) : []
+                libraryPath: libraryPath?.map(d => d[Id])
                 //collectionDockingView: CollectionDockingView.Instance
             }
         };
@@ -76,12 +75,12 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
     public StartOtherDrag(e: any, dragDocs: Doc[]) {
         let config: any;
         if (dragDocs.length === 1) {
-            config = CollectionDockingView.makeDocumentConfig(dragDocs[0], undefined);
+            config = CollectionDockingView.makeDocumentConfig(dragDocs[0]);
         } else {
             config = {
                 type: 'row',
                 content: dragDocs.map((doc, i) => {
-                    CollectionDockingView.makeDocumentConfig(doc, undefined);
+                    CollectionDockingView.makeDocumentConfig(doc);
                 })
             };
         }
@@ -97,10 +96,9 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
     @action
     public OpenFullScreen(docView: DocumentView, libraryPath?: Doc[]) {
         const document = Doc.MakeAlias(docView.props.Document);
-        const dataDoc = docView.props.DataDoc;
         const newItemStackConfig = {
             type: 'stack',
-            content: [CollectionDockingView.makeDocumentConfig(document, dataDoc, undefined, libraryPath)]
+            content: [CollectionDockingView.makeDocumentConfig(document, undefined, libraryPath)]
         };
         const docconfig = this._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, this._goldenLayout);
         this._goldenLayout.root.contentItems[0].addChild(docconfig);
@@ -172,7 +170,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
     }
     @undoBatch
     @action
-    public static ReplaceRightSplit(document: Doc, dataDoc: Doc | undefined, libraryPath?: Doc[], addToSplit?: boolean): boolean {
+    public static ReplaceRightSplit(document: Doc, libraryPath?: Doc[], addToSplit?: boolean): boolean {
         if (!CollectionDockingView.Instance) return false;
         const instance = CollectionDockingView.Instance;
         let retVal = false;
@@ -180,7 +178,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
             retVal = Array.from(instance._goldenLayout.root.contentItems[0].contentItems).some((child: any) => {
                 if (child.contentItems.length === 1 && child.contentItems[0].config.component === "DocumentFrameRenderer" &&
                     DocumentManager.Instance.getDocumentViewById(child.contentItems[0].config.props.documentId)?.Document.isDisplayPanel) {
-                    const newItemStackConfig = CollectionDockingView.makeDocumentConfig(document, dataDoc, undefined, libraryPath);
+                    const newItemStackConfig = CollectionDockingView.makeDocumentConfig(document, undefined, libraryPath);
                     child.addChild(newItemStackConfig, undefined);
                     !addToSplit && child.contentItems[0].remove();
                     instance.layoutChanged(document);
@@ -188,7 +186,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
                 }
                 return Array.from(child.contentItems).filter((tab: any) => tab.config.component === "DocumentFrameRenderer").some((tab: any, j: number) => {
                     if (DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId)?.Document.isDisplayPanel) {
-                        const newItemStackConfig = CollectionDockingView.makeDocumentConfig(document, dataDoc, undefined, libraryPath);
+                        const newItemStackConfig = CollectionDockingView.makeDocumentConfig(document, undefined, libraryPath);
                         child.addChild(newItemStackConfig, undefined);
                         !addToSplit && child.contentItems[j].remove();
                         instance.layoutChanged(document);
@@ -210,12 +208,12 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
     //
     @undoBatch
     @action
-    public static AddRightSplit(document: Doc, dataDoc: Doc | undefined, libraryPath?: Doc[]) {
+    public static AddRightSplit(document: Doc, libraryPath?: Doc[]) {
         if (!CollectionDockingView.Instance) return false;
         const instance = CollectionDockingView.Instance;
         const newItemStackConfig = {
             type: 'stack',
-            content: [CollectionDockingView.makeDocumentConfig(document, dataDoc, undefined, libraryPath)]
+            content: [CollectionDockingView.makeDocumentConfig(document, undefined, libraryPath)]
         };
 
         const newContentItem = instance._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout);
@@ -245,18 +243,18 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
     //
     @undoBatch
     @action
-    public static UseRightSplit(document: Doc, dataDoc: Doc | undefined, libraryPath?: Doc[], shiftKey?: boolean) {
+    public static UseRightSplit(document: Doc, libraryPath?: Doc[], shiftKey?: boolean) {
         document.isDisplayPanel = true;
-        if (shiftKey || !CollectionDockingView.ReplaceRightSplit(document, dataDoc, libraryPath, shiftKey)) {
-            CollectionDockingView.AddRightSplit(document, dataDoc, libraryPath);
+        if (shiftKey || !CollectionDockingView.ReplaceRightSplit(document, libraryPath, shiftKey)) {
+            CollectionDockingView.AddRightSplit(document, libraryPath);
         }
     }
 
     @undoBatch
     @action
-    public AddTab = (stack: any, document: Doc, dataDocument: Doc | undefined, libraryPath?: Doc[]) => {
+    public AddTab = (stack: any, document: Doc, libraryPath?: Doc[]) => {
         Doc.GetProto(document).lastOpened = new DateField;
-        const docContentConfig = CollectionDockingView.makeDocumentConfig(document, dataDocument, undefined, libraryPath);
+        const docContentConfig = CollectionDockingView.makeDocumentConfig(document, undefined, libraryPath);
         if (stack === undefined) {
             let stack: any = this._goldenLayout.root;
             while (!stack.isStack) {
@@ -427,7 +425,6 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
             }
 
             const doc = await DocServer.GetRefField(tab.contentItem.config.props.documentId) as Doc;
-            const dataDoc = await DocServer.GetRefField(tab.contentItem.config.props.dataDocumentId) as Doc;
             if (doc instanceof Doc) {
                 //tab.titleElement[0].outerHTML = `<input class='lm_title' style="background:black" value='${doc.title}' />`;
                 tab.titleElement[0].onclick = (e: any) => tab.titleElement[0].focus();
@@ -507,7 +504,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
         stack.header.element[0].style.backgroundColor = DocServer.Control.isReadOnly() ? "#228540" : undefined;
         stack.header.element.on('mousedown', (e: any) => {
             if (e.target === stack.header.element[0] && e.button === 1) {
-                this.AddTab(stack, Docs.Create.FreeformDocument([], { _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), title: "Untitled Collection" }), undefined);
+                this.AddTab(stack, Docs.Create.FreeformDocument([], { _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), title: "Untitled Collection" }));
             }
         });
 
@@ -580,7 +577,6 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
 
 interface DockedFrameProps {
     documentId: FieldId;
-    dataDocumentId: FieldId;
     glContainer: any;
     libraryPath: (FieldId[]);
     backgroundColor?: (doc: Doc) => string | undefined;
@@ -593,7 +589,6 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     @observable private _panelWidth = 0;
     @observable private _panelHeight = 0;
     @observable private _document: Opt<Doc>;
-    @observable private _dataDoc: Opt<Doc>;
     @observable private _isActive: boolean = false;
 
     get _stack(): any {
@@ -601,12 +596,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     }
     constructor(props: any) {
         super(props);
-        DocServer.GetRefField(this.props.documentId).then(action((f: Opt<Field>) => {
-            this._document = f as Doc;
-            if (this.props.dataDocumentId && this.props.documentId !== this.props.dataDocumentId) {
-                DocServer.GetRefField(this.props.dataDocumentId).then(action((f: Opt<Field>) => this._dataDoc = f as Doc));
-            }
-        }));
+        DocServer.GetRefField(this.props.documentId).then(action((f: Opt<Field>) => this._document = f as Doc));
         this.props.libraryPath && this.setupLibraryPath();
     }
 
@@ -630,7 +620,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             pinDoc.presentationTargetDoc = doc;
             Doc.AddDocToList(curPres, "data", pinDoc);
             if (!DocumentManager.Instance.getDocumentView(curPres)) {
-                CollectionDockingView.AddRightSplit(curPres, undefined);
+                CollectionDockingView.AddRightSplit(curPres);
             }
         }
     }
@@ -708,16 +698,16 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
     get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this.panelWidth() * 100}%` : undefined; }
 
-    addDocTab = (doc: Doc, dataDoc: Opt<Doc>, location: string, libraryPath?: Doc[]) => {
+    addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => {
         SelectionManager.DeselectAll();
         if (doc.dockingConfig) {
             return MainView.Instance.openWorkspace(doc);
         } else if (location === "onRight") {
-            return CollectionDockingView.AddRightSplit(doc, dataDoc, libraryPath);
+            return CollectionDockingView.AddRightSplit(doc, libraryPath);
         } else if (location === "close") {
             return CollectionDockingView.CloseRightSplit(doc);
         } else {
-            return CollectionDockingView.Instance.AddTab(this._stack, doc, dataDoc, libraryPath);
+            return CollectionDockingView.Instance.AddTab(this._stack, doc, libraryPath);
         }
     }
 
@@ -725,7 +715,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
         TraceMobx();
         if (!this._document) return (null);
         const document = this._document;
-        const resolvedDataDoc = document.layout instanceof Doc ? document : this._dataDoc;
+        const resolvedDataDoc = this._document[DataSym] !== this._document && this._document[DataSym];// document.layout instanceof Doc ? document : this._dataDoc;
         return <DocumentView key={document[Id]}
             LibraryPath={this._libraryPath}
             Document={document}
@@ -762,5 +752,5 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             </div >);
     }
 }
-Scripting.addGlobal(function openOnRight(doc: any) { CollectionDockingView.AddRightSplit(doc, undefined); });
-Scripting.addGlobal(function useRightSplit(doc: any, shiftKey?: boolean) { CollectionDockingView.UseRightSplit(doc, undefined, undefined, shiftKey); });
+Scripting.addGlobal(function openOnRight(doc: any) { CollectionDockingView.AddRightSplit(doc); });
+Scripting.addGlobal(function useRightSplit(doc: any, shiftKey?: boolean) { CollectionDockingView.UseRightSplit(doc, undefined, shiftKey); });
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index a3b1b5ec0..851fded71 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -35,7 +35,7 @@ export interface CellProps {
     Document: Doc;
     fieldKey: string;
     renderDepth: number;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     moveDocument: (document: Doc, targetCollection: Doc | undefined, 
     addDocument: (document: Doc) => boolean) => boolean;
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index c422c38f1..7dee7f18f 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -224,7 +224,7 @@ export interface SchemaTableProps {
     ScreenToLocalTransform: () => Transform;
     active: (outsideReaction: boolean) => boolean;
     onDrop: (e: React.DragEvent<Element>, options: DocumentOptions, completed?: (() => void) | undefined) => void;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     isSelected: (outsideReaction?: boolean) => boolean;
     isFocused: (document: Doc) => boolean;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index ad9dc8f7c..0d5d3e449 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -4,7 +4,7 @@ import { CursorProperty } from "csstype";
 import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import Switch from 'rc-switch';
-import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc";
+import { Doc, HeightSym, WidthSym, DataSym } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
@@ -62,7 +62,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap);
             const style = this.isStackingView ? { width: width(), marginTop: i === 0 ? 0 : this.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` };
             return <div className={`collectionStackingView-${this.isStackingView ? "columnDoc" : "masonryDoc"}`} key={d[Id]} ref={dref} style={style} >
-                {this.getDisplayDoc(d, Cast(d.resolvedDataDoc, Doc, null) || this.props.DataDoc, dxf, width)}
+                {this.getDisplayDoc(d, this.props.DataDoc, dxf, width)}
             </div>;
         });
     }
@@ -158,7 +158,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         const height = () => this.getDocHeight(doc);
         return <ContentFittingDocumentView
             Document={doc}
-            DataDocument={dataDoc}
+            DataDocument={doc[DataSym] !== doc && doc[DataSym]}
             backgroundColor={this.props.backgroundColor}
             LayoutDoc={this.props.childLayoutTemplate}
             LibraryPath={this.props.LibraryPath}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 13ab7c1a4..dd622bf9d 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -47,7 +47,7 @@ export interface TreeViewProps {
     deleteDoc: (doc: Doc) => boolean;
     moveDocument: DragManager.MoveFunction;
     dropAction: "alias" | "copy" | undefined;
-    addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string, libraryPath?: Doc[]) => boolean;
+    addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean;
     pinToPres: (document: Doc) => void;
     panelWidth: () => number;
     panelHeight: () => number;
@@ -128,7 +128,7 @@ class TreeView extends React.Component<TreeViewProps> {
     }
 
     @undoBatch delete = () => this.props.deleteDoc(this.props.document);
-    @undoBatch openRight = () => this.props.addDocTab(this.props.document, this.templateDataDoc, "onRight", this.props.libraryPath);
+    @undoBatch openRight = () => this.props.addDocTab(this.props.document, "onRight", this.props.libraryPath);
     @undoBatch indent = () => this.props.addDocument(this.props.document) && this.delete();
     @undoBatch move = (doc: Doc, target: Doc | undefined, addDoc: (doc: Doc) => boolean) => {
         return this.props.document !== target && this.props.deleteDoc(doc) && addDoc(doc);
@@ -201,8 +201,8 @@ class TreeView extends React.Component<TreeViewProps> {
                 ContextMenu.Instance.addItem({ description: "Clear All", event: () => Doc.GetProto(CurrentUserUtils.UserDocument.recentlyClosed as Doc).data = new List<Doc>(), icon: "plus" });
             } else if (this.props.document !== CurrentUserUtils.UserDocument.workspaces) {
                 ContextMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.document), icon: "tv" });
-                ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, this.templateDataDoc, "inTab", this.props.libraryPath), icon: "folder" });
-                ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, this.templateDataDoc, "onRight", this.props.libraryPath), icon: "caret-square-right" });
+                ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, "inTab", this.props.libraryPath), icon: "folder" });
+                ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, "onRight", this.props.libraryPath), icon: "caret-square-right" });
                 if (DocumentManager.Instance.getDocumentViews(this.dataDoc).length) {
                     ContextMenu.Instance.addItem({ description: "Focus", event: () => (view => view && view.props.focus(this.props.document, true))(DocumentManager.Instance.getFirstDocumentView(this.props.document)), icon: "camera" });
                 }
@@ -212,7 +212,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 ContextMenu.Instance.addItem({ description: "Create New Workspace", event: () => MainView.Instance.createNewWorkspace(), icon: "plus" });
             }
             ContextMenu.Instance.addItem({ description: "Toggle Theme Colors", event: () => this.props.document.darkScheme = !this.props.document.darkScheme, icon: "minus" });
-            ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { const kvp = Docs.Create.KVPDocument(this.props.document, { _width: 300, _height: 300 }); this.props.addDocTab(kvp, this.props.dataDoc ? this.props.dataDoc : kvp, "onRight"); }, icon: "layer-group" });
+            ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { const kvp = Docs.Create.KVPDocument(this.props.document, { _width: 300, _height: 300 }); this.props.addDocTab(kvp, "onRight"); }, icon: "layer-group" });
             ContextMenu.Instance.addItem({ description: "Publish", event: () => DocUtils.Publish(this.props.document, StrCast(this.props.document.title), () => { }, () => { }), icon: "file" });
             ContextMenu.Instance.displayMenu(e.pageX > 156 ? e.pageX - 156 : 0, e.pageY - 15);
             e.stopPropagation();
@@ -457,7 +457,7 @@ class TreeView extends React.Component<TreeViewProps> {
         remove: ((doc: Doc) => boolean),
         move: DragManager.MoveFunction,
         dropAction: dropActionType,
-        addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string) => boolean,
+        addDocTab: (doc: Doc, where: string) => boolean,
         pinToPres: (document: Doc) => void,
         backgroundColor: undefined | ((document: Doc) => string | undefined),
         screenToLocalXf: () => Transform,
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 79fd7d792..95f9fa62f 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -229,10 +229,10 @@ export class CollectionView extends Touchable<FieldViewProps> {
             const layoutItems = existing && "subitems" in existing ? existing.subitems : [];
             layoutItems.push({ description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" });
             if (this.props.Document.childLayout instanceof Doc) {
-                layoutItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, undefined, "onRight"), icon: "project-diagram" });
+                layoutItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, "onRight"), icon: "project-diagram" });
             }
             if (this.props.Document.childDetailed instanceof Doc) {
-                layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childDetailed as Doc, undefined, "onRight"), icon: "project-diagram" });
+                layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childDetailed as Doc, "onRight"), icon: "project-diagram" });
             }
             !existing && ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "hand-point-right" });
 
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index 027ac5a0e..43ba5c614 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -24,7 +24,7 @@ type SelectorProps = {
     Document: Doc,
     Views: DocumentView[],
     Stack?: any,
-    addDocTab(doc: Doc, dataDoc: Doc | undefined, location: string): void
+    addDocTab(doc: Doc, location: string): void
 };
 
 @observer
@@ -60,7 +60,7 @@ export class SelectorContextMenu extends React.Component<SelectorProps> {
                 col._panX = newPanX;
                 col._panY = newPanY;
             }
-            this.props.addDocTab(col, undefined, "inTab"); // bcz: dataDoc?
+            this.props.addDocTab(col, "inTab"); // bcz: dataDoc?
         };
     }
 
diff --git a/src/client/views/linking/LinkFollowBox.tsx b/src/client/views/linking/LinkFollowBox.tsx
index 325c92413..b47464517 100644
--- a/src/client/views/linking/LinkFollowBox.tsx
+++ b/src/client/views/linking/LinkFollowBox.tsx
@@ -183,9 +183,9 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
 
     }
 
-    static _addDocTab: (undefined | ((doc: Doc, dataDoc: Opt<Doc>, where: string) => boolean));
+    static _addDocTab: (undefined | ((doc: Doc, where: string) => boolean));
 
-    static setAddDocTab = (addFunc: (doc: Doc, dataDoc: Opt<Doc>, where: string) => boolean) => {
+    static setAddDocTab = (addFunc: (doc: Doc, where: string) => boolean) => {
         LinkFollowBox._addDocTab = addFunc;
     }
 
@@ -199,7 +199,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
                 options.context._panX = newPanX;
                 options.context._panY = newPanY;
             }
-            (LinkFollowBox._addDocTab || this.props.addDocTab)(options.context, undefined, "onRight");
+            (LinkFollowBox._addDocTab || this.props.addDocTab)(options.context, "onRight");
 
             if (options.shouldZoom) this.jumpToLink({ shouldZoom: options.shouldZoom });
 
@@ -212,7 +212,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
     openLinkRight = () => {
         if (LinkFollowBox.destinationDoc) {
             const alias = Doc.MakeAlias(LinkFollowBox.destinationDoc);
-            (LinkFollowBox._addDocTab || this.props.addDocTab)(alias, undefined, "onRight");
+            (LinkFollowBox._addDocTab || this.props.addDocTab)(alias, "onRight");
             this.highlightDoc();
             SelectionManager.DeselectAll();
         }
@@ -222,8 +222,8 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
     @undoBatch
     jumpToLink = async (options: { shouldZoom: boolean }) => {
         if (LinkFollowBox.sourceDoc && LinkFollowBox.linkDoc) {
-            const focus = (document: Doc) => { (LinkFollowBox._addDocTab || this.props.addDocTab)(document, undefined, "inTab"); SelectionManager.DeselectAll(); };
-            //let focus = (doc: Doc, maxLocation: string) => this.props.focus(docthis.props.focus(LinkFollowBox.destinationDoc, true, 1, () => this.props.addDocTab(doc, undefined, maxLocation));
+            const focus = (document: Doc) => { (LinkFollowBox._addDocTab || this.props.addDocTab)(document, "inTab"); SelectionManager.DeselectAll(); };
+            //let focus = (doc: Doc, maxLocation: string) => this.props.focus(docthis.props.focus(LinkFollowBox.destinationDoc, true, 1, () => this.props.addDocTab(doc, maxLocation));
 
             DocumentManager.Instance.FollowLink(LinkFollowBox.linkDoc, LinkFollowBox.sourceDoc, focus, options && options.shouldZoom, false, undefined);
         }
@@ -234,7 +234,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
         if (LinkFollowBox.destinationDoc) {
             const fullScreenAlias = Doc.MakeAlias(LinkFollowBox.destinationDoc);
             // this.prosp.addDocTab is empty -- use the link source's addDocTab 
-            (LinkFollowBox._addDocTab || this.props.addDocTab)(fullScreenAlias, undefined, "inTab");
+            (LinkFollowBox._addDocTab || this.props.addDocTab)(fullScreenAlias, "inTab");
 
             this.highlightDoc();
             SelectionManager.DeselectAll();
@@ -251,7 +251,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
                 options.context._panX = newPanX;
                 options.context._panY = newPanY;
             }
-            (LinkFollowBox._addDocTab || this.props.addDocTab)(options.context, undefined, "inTab");
+            (LinkFollowBox._addDocTab || this.props.addDocTab)(options.context, "inTab");
             if (options.shouldZoom) this.jumpToLink({ shouldZoom: options.shouldZoom });
 
             this.highlightDoc();
diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx
index 1a40f0c55..a8aa01306 100644
--- a/src/client/views/linking/LinkMenu.tsx
+++ b/src/client/views/linking/LinkMenu.tsx
@@ -16,7 +16,7 @@ library.add(faTrash);
 interface Props {
     docView: DocumentView;
     changeFlyout: () => void;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
 }
 
 @observer
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx
index 0c38ff45c..78c77e106 100644
--- a/src/client/views/linking/LinkMenuGroup.tsx
+++ b/src/client/views/linking/LinkMenuGroup.tsx
@@ -17,7 +17,7 @@ interface LinkMenuGroupProps {
     group: Doc[];
     groupType: string;
     showEditor: (linkDoc: Doc) => void;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
     docView: DocumentView;
 }
 
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index b7d27ee30..54f5636e4 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -20,7 +20,7 @@ interface LinkMenuItemProps {
     sourceDoc: Doc;
     destinationDoc: Doc;
     showEditor: (linkDoc: Doc) => void;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
 }
 
 @observer
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 73fe4fb5d..36233a7e6 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -34,7 +34,7 @@ interface ContentFittingDocumentViewProps {
     removeDocument?: (document: Doc) => boolean;
     active: (outsideReaction: boolean) => boolean;
     whenActiveChanged: (isActive: boolean) => void;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     dontRegisterView?: boolean;
 }
diff --git a/src/client/views/nodes/DocuLinkBox.tsx b/src/client/views/nodes/DocuLinkBox.tsx
index 156b16ec8..a0b5cd8ec 100644
--- a/src/client/views/nodes/DocuLinkBox.tsx
+++ b/src/client/views/nodes/DocuLinkBox.tsx
@@ -61,7 +61,7 @@ export class DocuLinkBox extends DocComponent<FieldViewProps, DocLinkSchema>(Doc
     onClick = (e: React.MouseEvent) => {
         if (!this.props.Document.onClick) {
             if (Math.abs(e.clientX - this._downx) < 3 && Math.abs(e.clientY - this._downy) < 3 && (e.button !== 2 && !e.ctrlKey && this.props.Document.isButton)) {
-                DocumentManager.Instance.FollowLink(this.props.Document, this.props.ContainingCollectionDoc as Doc, document => this.props.addDocTab(document, undefined, "inTab"), false);
+                DocumentManager.Instance.FollowLink(this.props.Document, this.props.ContainingCollectionDoc as Doc, document => this.props.addDocTab(document, "inTab"), false);
             }
             e.stopPropagation();
         }
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 11a33b70a..c0f603171 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -82,7 +82,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
         return this.props.DataDoc instanceof Promise ? undefined : this.props.DataDoc;
     }
     get layoutDoc() {
-        if (this.props.DataDoc === undefined && (this.props.LayoutDoc || typeof Doc.LayoutField(this.props.Document) !== "string")) {
+        if (this.props.LayoutDoc || (this.props.DataDoc === undefined && typeof Doc.LayoutField(this.props.Document) !== "string")) {
             // if there is no dataDoc (ie, we're not rendering a template layout), but this document has a layout document (not a layout string), 
             // then we render the layout document as a template and use this document as the data context for the template layout.
             return Doc.expandTemplateLayout(this.props.LayoutDoc?.() || Doc.Layout(this.props.Document), this.props.Document);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 566c0d5de..dea08600a 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -71,7 +71,7 @@ export interface DocumentViewProps {
     parentActive: (outsideReaction: boolean) => boolean;
     whenActiveChanged: (isActive: boolean) => void;
     bringToFront: (doc: Doc, sendToBack?: boolean) => void;
-    addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string, libraryPath?: Doc[]) => boolean;
+    addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean;
     pinToPres: (document: Doc) => void;
     zoomToScale: (scale: number) => void;
     backgroundHalo?: () => boolean;
@@ -152,9 +152,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     //     RadialMenu.Instance.openMenu();
 
-    //     RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group", selected: -1 });
+    //     RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), "onRight"), icon: "layer-group", selected: -1 });
     //     RadialMenu.Instance.addItem({ description: "Delete this document", event: () => this.props.ContainingCollectionView?.removeDocument(this.props.Document), icon: "trash", selected: -1 });
-    //     RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, undefined, "onRight"), icon: "folder", selected: -1 });
+    //     RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, "onRight"), icon: "folder", selected: -1 });
     //     RadialMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.Document), icon: "map-pin", selected: -1 });
 
     //     RadialMenu.Instance.displayMenu(pt.pageX - 15, pt.pageY - 15);
@@ -253,7 +253,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 if (StrCast(fullScreenAlias.layoutKey) !== "layout_fullScreen" && fullScreenAlias.layout_fullScreen) {
                     fullScreenAlias.layoutKey = "layout_fullScreen";
                 }
-                UndoManager.RunInBatch(() => this.props.addDocTab(fullScreenAlias, undefined, "inTab"), "double tap");
+                UndoManager.RunInBatch(() => this.props.addDocTab(fullScreenAlias, "inTab"), "double tap");
                 SelectionManager.DeselectAll();
                 Doc.UnBrushDoc(this.props.Document);
             } else if (this.onClickHandler && this.onClickHandler.script) {
@@ -277,7 +277,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         if (linkDocs.length) {
             DocumentManager.Instance.FollowLink(undefined, this.props.Document,
                 // open up target if it's not already in view ... by zooming into the button document first and setting flag to reset zoom afterwards
-                (doc: Doc, maxLocation: string) => this.props.focus(this.props.Document, true, 1, () => this.props.addDocTab(doc, undefined, maxLocation)),
+                (doc: Doc, maxLocation: string) => this.props.focus(this.props.Document, true, 1, () => this.props.addDocTab(doc, maxLocation)),
                 ctrlKey, altKey, this.props.ContainingCollectionDoc);
         }
     }
@@ -644,12 +644,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const open = ContextMenu.Instance.findByDescription("Open...");
         const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : [];
         openItems.push({ description: "Open Full Screen", event: () => CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(this, this.props.LibraryPath), icon: "desktop" });
-        openItems.push({ description: "Open Tab        ", event: () => this.props.addDocTab(this.props.Document, this.props.DataDoc, "inTab", this.props.LibraryPath), icon: "folder" });
-        openItems.push({ description: "Open Right      ", event: () => this.props.addDocTab(this.props.Document, this.props.DataDoc, "onRight", this.props.LibraryPath), icon: "caret-square-right" });
-        openItems.push({ description: "Open Alias Tab  ", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.props.DataDoc, "inTab"), icon: "folder" });
-        openItems.push({ description: "Open Alias Right", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.props.DataDoc, "onRight"), icon: "caret-square-right" });
-        openItems.push({ description: "Open Fields     ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), undefined, "onRight"), icon: "layer-group" });
-        templateDoc && openItems.push({ description: "Open Template   ", event: () => this.props.addDocTab(templateDoc, undefined, "onRight"), icon: "eye" });
+        openItems.push({ description: "Open Tab        ", event: () => this.props.addDocTab(this.props.Document, "inTab", this.props.LibraryPath), icon: "folder" });
+        openItems.push({ description: "Open Right      ", event: () => this.props.addDocTab(this.props.Document, "onRight", this.props.LibraryPath), icon: "caret-square-right" });
+        openItems.push({ description: "Open Alias Tab  ", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), "inTab"), icon: "folder" });
+        openItems.push({ description: "Open Alias Right", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), "onRight"), icon: "caret-square-right" });
+        openItems.push({ description: "Open Fields     ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
+        templateDoc && openItems.push({ description: "Open Template   ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" });
         openItems.push({ description: "Open Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) });
         !open && cm.addItem({ description: "Open...", subitems: openItems, icon: "external-link-alt" });
 
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 00f00dd52..f5c85e143 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -29,7 +29,7 @@ export interface FieldViewProps {
     select: (isCtrlPressed: boolean) => void;
     renderDepth: number;
     addDocument?: (document: Doc) => boolean;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     removeDocument?: (document: Doc) => boolean;
     moveDocument?: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean;
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index a191ac4f4..d4da21239 100644
--- a/src/client/views/nodes/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox.tsx
@@ -36,7 +36,7 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
 
     showTemplate = (): void => {
         const dragFactory = Cast(this.props.Document.dragFactory, Doc, null);
-        dragFactory && this.props.addDocTab(dragFactory, undefined, "onRight");
+        dragFactory && this.props.addDocTab(dragFactory, "onRight");
     }
 
     specificContextMenu = (): void => {
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index fd288f720..842ccdd7b 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -916,7 +916,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
         //             if (linkClicked) {
         //                 DocServer.GetRefField(linkClicked).then(async linkDoc => {
         //                     (linkDoc instanceof Doc) &&
-        //                         DocumentManager.Instance.FollowLink(linkDoc, this.props.Document, document => this.props.addDocTab(document, undefined, location ? location : "inTab"), false);
+        //                         DocumentManager.Instance.FollowLink(linkDoc, this.props.Document, document => this.props.addDocTab(document, location ? location : "inTab"), false);
         //                 });
         //             }
         //         } else {
diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx
index fda3e3285..1174110e7 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/FormattedTextBoxComment.tsx
@@ -84,9 +84,9 @@ export class FormattedTextBoxComment {
                 const textBox = FormattedTextBoxComment.textBox;
                 if (FormattedTextBoxComment.linkDoc && !keep && textBox) {
                     DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document,
-                        (doc: Doc, maxLocation: string) => textBox.props.addDocTab(doc, undefined, e.ctrlKey ? "inTab" : "onRight"));
+                        (doc: Doc, maxLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : "onRight"));
                 } else if (textBox && (FormattedTextBoxComment.tooltipText as any).href) {
-                    textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400 }), undefined, "onRight");
+                    textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400 }), "onRight");
                 }
                 keep && textBox && FormattedTextBoxComment.start !== undefined && textBox.adoptAnnotation(
                     FormattedTextBoxComment.start, FormattedTextBoxComment.end, FormattedTextBoxComment.mark);
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index e6b512adf..93bda6d02 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -22,7 +22,7 @@ export interface KeyValuePairProps {
     keyWidth: number;
     PanelHeight: () => number;
     PanelWidth: () => number;
-    addDocTab: (doc: Doc, data: Opt<Doc>, where: string) => boolean;
+    addDocTab: (doc: Doc, where: string) => boolean;
 }
 @observer
 export class KeyValuePair extends React.Component<KeyValuePairProps> {
@@ -46,7 +46,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
         if (value instanceof Doc) {
             e.stopPropagation();
             e.preventDefault();
-            ContextMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(value, { _width: 300, _height: 300 }), undefined, "onRight"), icon: "layer-group" });
+            ContextMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(value, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
             ContextMenu.Instance.displayMenu(e.clientX, e.clientY);
         }
     }
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index d4a47c159..8d20bbe59 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -327,12 +327,12 @@ export class PresBox extends React.Component<FieldViewProps> {
         if (toggle) {
             if (this.props.Document.inOverlay) {
                 Doc.RemoveDocFromList((CurrentUserUtils.UserDocument.overlays as Doc), this.props.fieldKey, this.props.Document);
-                CollectionDockingView.AddRightSplit(this.props.Document, this.props.DataDoc);
+                CollectionDockingView.AddRightSplit(this.props.Document);
                 this.props.Document.inOverlay = false;
             } else {
                 this.props.Document.x = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[0];// 500;//e.clientX + 25;
                 this.props.Document.y = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[1];////e.clientY - 25;
-                this.props.addDocTab && this.props.addDocTab(this.props.Document, this.props.DataDoc, "close");
+                this.props.addDocTab?.(this.props.Document, "close");
                 Doc.AddDocToList((CurrentUserUtils.UserDocument.overlays as Doc), this.props.fieldKey, this.props.Document);
             }
         }
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 6695e04c3..69c6f2617 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -90,7 +90,7 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
     @action public FullScreen() {
         this._fullScreen = true;
         this.player && this.player.requestFullscreen();
-        this._youtubePlayer && this.props.addDocTab(this.props.Document, this.props.DataDoc, "inTab");
+        this._youtubePlayer && this.props.addDocTab(this.props.Document, "inTab");
     }
 
     choosePath(url: string) {
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index d8b340db6..58823c93d 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -11,7 +11,7 @@ import "./Annotation.scss";
 
 interface IAnnotationProps {
     anno: Doc;
-    addDocTab: (document: Doc, dataDoc: Opt<Doc>, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     focus: (doc: Doc) => void;
     dataDoc: Doc;
@@ -30,7 +30,7 @@ interface IRegionAnnotationProps {
     y: number;
     width: number;
     height: number;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     document: Doc;
     dataDoc: Doc;
@@ -98,7 +98,7 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
             const annoGroup = await Cast(this.props.document.group, Doc);
             if (annoGroup) {
                 DocumentManager.Instance.FollowLink(undefined, annoGroup,
-                    (doc: Doc, maxLocation: string) => this.props.addDocTab(doc, undefined, e.ctrlKey ? "inTab" : "onRight"),
+                    (doc: Doc, maxLocation: string) => this.props.addDocTab(doc, e.ctrlKey ? "inTab" : "onRight"),
                     false, false, undefined);
                 e.stopPropagation();
             }
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index a9b8c6bbe..198aeb856 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -65,7 +65,7 @@ interface IViewerProps {
     loaded: (nw: number, nh: number, np: number) => void;
     active: (outsideReaction?: boolean) => boolean;
     isChildActive: (outsideReaction?: boolean) => boolean;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     addDocument?: (doc: Doc) => boolean;
     setPdfViewer: (view: PDFViewer) => void;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 888707ee3..8d62c34c5 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -4,7 +4,7 @@ import { faArrowDown, faArrowUp, faFile as fileSolid, faFileDownload, faLocation
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { action, computed, IReactionDisposer, reaction } from "mobx";
 import { observer } from "mobx-react";
-import { Doc } from "../../../new_fields/Doc";
+import { Doc, DataSym } from "../../../new_fields/Doc";
 import { documentSchema } from '../../../new_fields/documentSchemas';
 import { Id } from "../../../new_fields/FieldSymbols";
 import { createSchema, makeInterface } from '../../../new_fields/Schema';
@@ -173,6 +173,7 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
             <div className="presElementBox-embedded" style={{ height: this.embedHeight() }}>
                 <ContentFittingDocumentView
                     Document={this.targetDoc}
+                    DataDocument={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
                     LibraryPath={emptyPath}
                     fitToBox={true}
                     addDocument={returnFalse}
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 827cb80c6..2cbb24da7 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -74,7 +74,7 @@ export class SelectorContextMenu extends React.Component<SearchItemProps> {
                 col._panX = newPanX;
                 col._panY = newPanY;
             }
-            CollectionDockingView.AddRightSplit(col, undefined);
+            CollectionDockingView.AddRightSplit(col);
         };
     }
     render() {
@@ -108,7 +108,7 @@ export class LinkContextMenu extends React.Component<LinkMenuProps> {
 
     unHighlightDoc = (doc: Doc) => () => Doc.UnBrushDoc(doc);
 
-    getOnClick = (col: Doc) => () => CollectionDockingView.AddRightSplit(col, undefined);
+    getOnClick = (col: Doc) => () => CollectionDockingView.AddRightSplit(col);
 
     render() {
         return (
@@ -272,7 +272,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
 
     @computed
     get contextButton() {
-        return <ParentDocSelector Views={DocumentManager.Instance.DocumentViews} Document={this.props.doc} addDocTab={(doc, data, where) => CollectionDockingView.AddRightSplit(doc, data)} />;
+        return <ParentDocSelector Views={DocumentManager.Instance.DocumentViews} Document={this.props.doc} addDocTab={(doc, where) => CollectionDockingView.AddRightSplit(doc)} />;
     }
 
     render() {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 43bbea623..1f2dd1c8f 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -17,6 +17,7 @@ import { listSpec } from "./Schema";
 import { ComputedField } from "./ScriptField";
 import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types";
 import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util";
+import { DatasetAbout } from "../client/northstar/model/idea/idea";
 
 export namespace Field {
     export function toKeyValueString(doc: Doc, key: string): string {
@@ -495,7 +496,8 @@ export namespace Doc {
     // if the childDoc is a template for a field, then this will return the expanded layout with its data doc.
     // otherwise, it just returns the childDoc
     export function GetLayoutDataDocPair(containerDoc: Doc, containerDataDoc: Opt<Doc>, childDoc: Doc) {
-        const resolvedDataDoc = containerDataDoc === containerDoc || !containerDataDoc || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc;
+        const existingResolvedDataDoc = childDoc[DataSym] !== Doc.GetProto(childDoc)[DataSym] && childDoc[DataSym];
+        const resolvedDataDoc = existingResolvedDataDoc || (containerDataDoc === containerDoc || !containerDataDoc || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc);
         return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc), data: resolvedDataDoc };
     }
     export function CreateDocumentExtensionForField(doc: Doc, fieldKey: string) {
-- 
cgit v1.2.3-70-g09d2


From 1c73798b14bc91e59ab95225b341008271d0159a Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 22 Feb 2020 01:04:55 -0500
Subject: removed LinkFollow box.

---
 src/client/documents/DocumentTypes.ts              |   1 -
 src/client/documents/Documents.ts                  |   8 -
 src/client/views/OverlayView.tsx                   |   2 +-
 .../views/collections/CollectionLinearView.tsx     |   2 +-
 .../views/collections/CollectionStackingView.tsx   |   2 +-
 .../views/collections/CollectionTreeView.tsx       |   1 -
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   6 +-
 src/client/views/linking/LinkFollowBox.scss        |  93 ----
 src/client/views/linking/LinkFollowBox.tsx         | 571 ---------------------
 src/client/views/linking/LinkMenuItem.tsx          |   1 -
 src/client/views/nodes/DocumentContentsView.tsx    |   3 +-
 .../authentication/models/current_user_utils.ts    |   2 -
 12 files changed, 7 insertions(+), 685 deletions(-)
 delete mode 100644 src/client/views/linking/LinkFollowBox.scss
 delete mode 100644 src/client/views/linking/LinkFollowBox.tsx

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

diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index 0e6b59b33..06b15d78c 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -19,7 +19,6 @@ export enum DocumentType {
     WEBCAM = "webcam",
     FONTICON = "fonticonbox",
     PRES = "presentation",
-    LINKFOLLOW = "linkfollow",
     PRESELEMENT = "preselement",
     QUERY = "search",
     COLOR = "color",
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index aed14e4f6..ff64489bb 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -40,7 +40,6 @@ import { PresBox } from "../views/nodes/PresBox";
 import { ComputedField, ScriptField } from "../../new_fields/ScriptField";
 import { ProxyField } from "../../new_fields/Proxy";
 import { DocumentType } from "./DocumentTypes";
-import { LinkFollowBox } from "../views/linking/LinkFollowBox";
 import { PresElementBox } from "../views/presentationview/PresElementBox";
 import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
 import { QueryBox } from "../views/nodes/QueryBox";
@@ -250,9 +249,6 @@ export namespace Docs {
                 layout: { view: FontIconBox, dataField: data },
                 options: { _width: 40, _height: 40, borderRounding: "100%" },
             }],
-            [DocumentType.LINKFOLLOW, {
-                layout: { view: LinkFollowBox, dataField: data }
-            }],
             [DocumentType.WEBCAM, {
                 layout: { view: DashWebRTCVideo, dataField: data }
             }],
@@ -658,10 +654,6 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.FONTICON), undefined, { ...(options || {}) });
         }
 
-        export function LinkFollowBoxDocument(options?: DocumentOptions) {
-            return InstanceFromProto(Prototypes.get(DocumentType.LINKFOLLOW), undefined, { ...(options || {}) });
-        }
-
         export function PresElementBoxDocument(options?: DocumentOptions) {
             return InstanceFromProto(Prototypes.get(DocumentType.PRESELEMENT), undefined, { ...(options || {}) });
         }
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 7a99bf0ae..220efd4a8 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -169,7 +169,7 @@ export class OverlayView extends React.Component {
                 document.addEventListener("pointermove", onPointerMove);
                 document.addEventListener("pointerup", onPointerUp);
             };
-            return <div className="overlayView-doc" key={d[Id]} onPointerDown={onPointerDown} style={{ transform: `translate(${d.x}px, ${d.y}px)`, display: d.isMinimized ? "none" : "" }}>
+            return <div className="overlayView-doc" key={d[Id]} onPointerDown={onPointerDown} style={{ transform: `translate(${d.x}px, ${d.y}px)` }}>
                 <DocumentView
                     Document={d}
                     LibraryPath={emptyPath}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 9bbc9f1b6..4a14a30cd 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -71,7 +71,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
         }
     }
 
-    public isCurrent(doc: Doc) { return !doc.isMinimized && (Math.abs(NumCast(doc.displayTimecode, -1) - NumCast(this.Document.currentTimecode, -1)) < 1.5 || NumCast(doc.displayTimecode, -1) === -1); }
+    public isCurrent(doc: Doc) { return (Math.abs(NumCast(doc.displayTimecode, -1) - NumCast(this.Document.currentTimecode, -1)) < 1.5 || NumCast(doc.displayTimecode, -1) === -1); }
 
     dimension = () => NumCast(this.props.Document._height); // 2 * the padding
     getTransform = (ele: React.RefObject<HTMLDivElement>) => () => {
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 0d5d3e449..a1cc21319 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -38,7 +38,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @observable _scroll = 0; // used to force the document decoration to update when scrolling
     @computed get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); }
     @computed get sectionFilter() { return StrCast(this.props.Document.sectionFilter); }
-    @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc && !pair.layout.isMinimized).map(pair => pair.layout); }
+    @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc).map(pair => pair.layout); }
     @computed get xMargin() { return NumCast(this.props.Document._xMargin, 2 * Math.min(this.gridGap, .05 * this.props.PanelWidth())); }
     @computed get yMargin() { return Math.max(this.props.Document._showTitle && !this.props.Document._showTitleHover ? 30 : 0, NumCast(this.props.Document._yMargin, 0)); } // 2 * this.gridGap)); }
     @computed get gridGap() { return NumCast(this.props.Document._gridGap, 10); }
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index ed1d674c6..7eeeb6ff1 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -421,7 +421,6 @@ class TreeView extends React.Component<TreeViewProps> {
         return <>
             <div className="docContainer" title="click to edit title" id={`docContainer-${this.props.parentKey}`} ref={reference} onPointerDown={onItemDown}
                 style={{
-                    color: this.props.document.isMinimized ? "red" : "inherit",
                     background: Doc.IsHighlighted(this.props.document) ? "orange" : Doc.IsBrushed(this.props.document) ? "#06121212" : "0",
                     fontWeight: this.props.document.searchMatch ? "bold" : undefined,
                     outline: BoolCast(this.props.document.workspaceBrush) ? "dashed 1px #06123232" : undefined,
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 5902cc22e..4458c7dcf 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -111,7 +111,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         SelectionManager.DeselectAll();
         docs.map(doc => DocumentManager.Instance.getDocumentView(doc)).map(dv => dv && SelectionManager.SelectDoc(dv, true));
     }
-    public isCurrent(doc: Doc) { return !doc.isMinimized && (Math.abs(NumCast(doc.displayTimecode, -1) - NumCast(this.Document.currentTimecode, -1)) < 1.5 || NumCast(doc.displayTimecode, -1) === -1); }
+    public isCurrent(doc: Doc) { return (Math.abs(NumCast(doc.displayTimecode, -1) - NumCast(this.Document.currentTimecode, -1)) < 1.5 || NumCast(doc.displayTimecode, -1) === -1); }
 
     public getActiveDocuments = () => {
         return this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout);
@@ -433,7 +433,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
         let x = this.Document._panX || 0;
         let y = this.Document._panY || 0;
-        const docs = this.childLayoutPairs.filter(pair => pair.layout instanceof Doc && !pair.layout.isMinimized).map(pair => pair.layout);
+        const docs = this.childLayoutPairs.filter(pair => pair.layout instanceof Doc).map(pair => pair.layout);
         const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
         if (!this.isAnnotationOverlay && docs.length && this.childDataProvider(docs[0])) {
             PDFMenu.Instance.fadeOut(true);
@@ -869,7 +869,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             }));
         this._cachedPool.clear();
         Array.from(newPool.keys()).forEach(k => this._cachedPool.set(k, newPool.get(k)));
-        const elements:ViewDefResult[] = computedElementData.slice();
+        const elements: ViewDefResult[] = computedElementData.slice();
         this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).forEach(pair =>
             elements.push({
                 ele: <CollectionFreeFormDocumentView key={pair.layout[Id]}  {...this.getChildDocumentViewProps(pair.layout, pair.data)}
diff --git a/src/client/views/linking/LinkFollowBox.scss b/src/client/views/linking/LinkFollowBox.scss
deleted file mode 100644
index 9eeed1cc8..000000000
--- a/src/client/views/linking/LinkFollowBox.scss
+++ /dev/null
@@ -1,93 +0,0 @@
-@import "../globalCssVariables";
-
-.linkFollowBox-main {
-    position: absolute;
-    background: whitesmoke;
-    color: grey;
-    border-radius: 15px;
-    box-shadow: $intermediate-color 0.2vw 0.2vw 0.4vw;
-    border: solid #BBBBBBBB 5px;
-    pointer-events: all;
-
-    .linkFollowBox-header {
-        height: 50px;
-        text-align: center;
-        text-transform: uppercase;
-        letter-spacing: 2px;
-        font-size: 16px;
-        width: 100%;
-    }
-
-    .direction-indicator {
-        font-size: 12px;
-    }
-
-    .closeDocument {
-        position: relative;
-        max-width: 30px;
-        top: -20px;
-        left: 460px;
-        color: $darker-alt-accent
-    }
-
-    .closeDocument:hover {
-        color: $main-accent;
-    }
-
-    .topHeader {
-        width: 100%;
-        height: 25px;
-    }
-
-    .linkFollowBox-footer {
-        height: 50px;
-        text-align: center;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-
-        button {
-            background-color: $darker-alt-accent;
-            width: 30%;
-        }
-    }
-
-    .linkFollowBox-content {
-        display: grid;
-        grid-template-columns: 1fr 1fr 1fr;
-        grid-column-gap: 5px;
-        margin-left: 5px;
-        margin-right: 5px;
-
-        .linkFollowBox-item {
-            background-color: $light-color;
-            width: 100%;
-            height: 100%;
-
-            .linkFollowBox-itemContent {
-                padding: 5px;
-                font-size: 12px;
-                overflow: scroll;
-
-                input[type=radio] {
-                    border: 0px;
-                    margin-right: 5px;
-                }
-            }
-
-            .title {
-                display: flex;
-                justify-content: center;
-                align-items: center;
-                text-transform: uppercase;
-                color: $light-color;
-                background-color: $lighter-alt-accent;
-                width: 100%;
-                height: 30px;
-                border-bottom: solid $darker-alt-accent 5px;
-                font-size: 12px;
-                text-align: center;
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/linking/LinkFollowBox.tsx b/src/client/views/linking/LinkFollowBox.tsx
deleted file mode 100644
index b47464517..000000000
--- a/src/client/views/linking/LinkFollowBox.tsx
+++ /dev/null
@@ -1,571 +0,0 @@
-import { observable, computed, action, runInAction, reaction, IReactionDisposer } from "mobx";
-import React = require("react");
-import { observer } from "mobx-react";
-import { FieldViewProps, FieldView } from "../nodes/FieldView";
-import { Doc, DocListCastAsync, Opt } from "../../../new_fields/Doc";
-import { undoBatch } from "../../util/UndoManager";
-import { NumCast, FieldValue, Cast, StrCast } from "../../../new_fields/Types";
-import { CollectionViewType } from "../collections/CollectionView";
-import { CollectionDockingView } from "../collections/CollectionDockingView";
-import { SelectionManager } from "../../util/SelectionManager";
-import { DocumentManager } from "../../util/DocumentManager";
-import { DocumentView } from "../nodes/DocumentView";
-import "./LinkFollowBox.scss";
-import { SearchUtil } from "../../util/SearchUtil";
-import { Id } from "../../../new_fields/FieldSymbols";
-import { listSpec } from "../../../new_fields/Schema";
-import { DocServer } from "../../DocServer";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faTimes } from '@fortawesome/free-solid-svg-icons';
-import { docs_v1 } from "googleapis";
-import { Utils } from "../../../Utils";
-import { Link } from "@react-pdf/renderer";
-
-enum FollowModes {
-    OPENTAB = "Open in Tab",
-    OPENRIGHT = "Open in Right Split",
-    OPENFULL = "Open Full Screen",
-    PAN = "Pan to Document",
-    INPLACE = "Open In Place"
-}
-
-enum FollowOptions {
-    ZOOM = "Zoom",
-    NOZOOM = "No Zoom",
-}
-
-@observer
-export class LinkFollowBox extends React.Component<FieldViewProps> {
-
-    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkFollowBox, fieldKey); }
-    public static Instance: LinkFollowBox | undefined;
-    @observable static linkDoc: Doc | undefined = undefined;
-    @observable static destinationDoc: Doc | undefined = undefined;
-    @observable static sourceDoc: Doc | undefined = undefined;
-    @observable selectedMode: string = "";
-    @observable selectedContext: Doc | undefined = undefined;
-    @observable selectedContextAliases: Doc[] | undefined = undefined;
-    @observable selectedOption: string = "";
-    @observable selectedContextString: string = "";
-    @observable sourceView: DocumentView | undefined = undefined;
-    @observable canPan: boolean = false;
-    @observable shouldUseOnlyParentContext = false;
-    _contextDisposer?: IReactionDisposer;
-
-    @observable private _docs: { col: Doc, target: Doc }[] = [];
-    @observable private _otherDocs: { col: Doc, target: Doc }[] = [];
-
-    constructor(props: FieldViewProps) {
-        super(props);
-        LinkFollowBox.Instance = this;
-        this.resetVars();
-        this.props.Document.isBackground = true;
-    }
-
-    componentDidMount = () => {
-        this.resetVars();
-
-        this._contextDisposer = reaction(
-            () => this.selectedContextString,
-            async () => {
-                const ref = await DocServer.GetRefField(this.selectedContextString);
-                runInAction(() => {
-                    if (ref instanceof Doc) {
-                        this.selectedContext = ref;
-                    }
-                });
-                if (this.selectedContext instanceof Doc) {
-                    const aliases = await SearchUtil.GetViewsOfDocument(this.selectedContext);
-                    runInAction(() => { this.selectedContextAliases = aliases; });
-                }
-            }
-        );
-    }
-
-    componentWillUnmount = () => {
-        this._contextDisposer && this._contextDisposer();
-    }
-
-    async resetPan() {
-        if (LinkFollowBox.destinationDoc && this.sourceView && this.sourceView.props.ContainingCollectionDoc) {
-            runInAction(() => this.canPan = false);
-            if (this.sourceView.props.ContainingCollectionDoc._viewType === CollectionViewType.Freeform) {
-                const docs = Cast(this.sourceView.props.ContainingCollectionDoc.data, listSpec(Doc), []);
-                const aliases = await SearchUtil.GetViewsOfDocument(Doc.GetProto(LinkFollowBox.destinationDoc));
-
-                aliases.forEach(alias => {
-                    if (docs.filter(doc => doc === alias).length > 0) {
-                        runInAction(() => { this.canPan = true; });
-                    }
-                });
-            }
-        }
-    }
-
-    @action
-    resetVars = () => {
-        this.selectedContext = undefined;
-        this.selectedContextString = "";
-        this.selectedMode = "";
-        this.selectedOption = "";
-        LinkFollowBox.linkDoc = undefined;
-        LinkFollowBox.sourceDoc = undefined;
-        LinkFollowBox.destinationDoc = undefined;
-        this.sourceView = undefined;
-        this.canPan = false;
-        this.shouldUseOnlyParentContext = false;
-    }
-
-    async fetchDocuments() {
-        if (LinkFollowBox.destinationDoc) {
-            const dest: Doc = LinkFollowBox.destinationDoc;
-            const aliases = await SearchUtil.GetViewsOfDocument(Doc.GetProto(dest));
-            const { docs } = await SearchUtil.Search("", true, { fq: `data_l:"${dest[Id]}"` });
-            const map: Map<Doc, Doc> = new Map;
-            const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search("", true, { fq: `data_l:"${doc[Id]}"` }).then(result => result.docs)));
-            allDocs.forEach((docs, index) => docs.forEach(doc => map.set(doc, aliases[index])));
-            docs.forEach(doc => map.delete(doc));
-            runInAction(async () => {
-                this._docs = docs.filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance.props.Document)).map(doc => ({ col: doc, target: dest }));
-                this._otherDocs = Array.from(map.entries()).filter(entry => !Doc.AreProtosEqual(entry[0], CollectionDockingView.Instance.props.Document)).map(([col, target]) => ({ col, target }));
-                const tcontext = LinkFollowBox.linkDoc && (await Cast(LinkFollowBox.linkDoc.anchor2Context, Doc)) as Doc;
-                runInAction(() => tcontext && this._docs.splice(0, 0, { col: tcontext, target: dest }));
-            });
-        }
-    }
-
-    @action
-    setLinkDocs = (linkDoc: Doc, source: Doc, dest: Doc) => {
-        this.resetVars();
-
-        LinkFollowBox.linkDoc = linkDoc;
-        LinkFollowBox.sourceDoc = source;
-        LinkFollowBox.destinationDoc = dest;
-        this.fetchDocuments();
-
-        SelectionManager.SelectedDocuments().forEach(dv => {
-            if (dv.props.Document === LinkFollowBox.sourceDoc) {
-                this.sourceView = dv;
-            }
-        });
-
-        this.resetPan();
-    }
-
-    highlightDoc = () => LinkFollowBox.destinationDoc && Doc.linkFollowHighlight(LinkFollowBox.destinationDoc);
-
-    @undoBatch
-    openFullScreen = () => {
-        if (LinkFollowBox.destinationDoc) {
-            const view = DocumentManager.Instance.getDocumentView(LinkFollowBox.destinationDoc);
-            view && CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(view);
-        }
-    }
-
-    @undoBatch
-    openColFullScreen = (options: { context: Doc }) => {
-        if (LinkFollowBox.destinationDoc) {
-            if (NumCast(options.context._viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) {
-                const newPanX = NumCast(LinkFollowBox.destinationDoc.x) + NumCast(LinkFollowBox.destinationDoc._width) / 2;
-                const newPanY = NumCast(LinkFollowBox.destinationDoc.y) + NumCast(LinkFollowBox.destinationDoc._height) / 2;
-                options.context._panX = newPanX;
-                options.context._panY = newPanY;
-            }
-            const view = DocumentManager.Instance.getDocumentView(options.context);
-            view && CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(view);
-            this.highlightDoc();
-        }
-    }
-
-    // should container be a doc or documentview or what? This one needs work and is more long term
-    @undoBatch
-    openInContainer = (options: { container: Doc }) => {
-
-    }
-
-    static _addDocTab: (undefined | ((doc: Doc, where: string) => boolean));
-
-    static setAddDocTab = (addFunc: (doc: Doc, where: string) => boolean) => {
-        LinkFollowBox._addDocTab = addFunc;
-    }
-
-    @undoBatch
-    openLinkColRight = (options: { context: Doc, shouldZoom: boolean }) => {
-        if (LinkFollowBox.destinationDoc) {
-            options.context = Doc.IsPrototype(options.context) ? Doc.MakeDelegate(options.context) : options.context;
-            if (NumCast(options.context._viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) {
-                const newPanX = NumCast(LinkFollowBox.destinationDoc.x) + NumCast(LinkFollowBox.destinationDoc._width) / 2;
-                const newPanY = NumCast(LinkFollowBox.destinationDoc.y) + NumCast(LinkFollowBox.destinationDoc._height) / 2;
-                options.context._panX = newPanX;
-                options.context._panY = newPanY;
-            }
-            (LinkFollowBox._addDocTab || this.props.addDocTab)(options.context, "onRight");
-
-            if (options.shouldZoom) this.jumpToLink({ shouldZoom: options.shouldZoom });
-
-            this.highlightDoc();
-            SelectionManager.DeselectAll();
-        }
-    }
-
-    @undoBatch
-    openLinkRight = () => {
-        if (LinkFollowBox.destinationDoc) {
-            const alias = Doc.MakeAlias(LinkFollowBox.destinationDoc);
-            (LinkFollowBox._addDocTab || this.props.addDocTab)(alias, "onRight");
-            this.highlightDoc();
-            SelectionManager.DeselectAll();
-        }
-
-    }
-
-    @undoBatch
-    jumpToLink = async (options: { shouldZoom: boolean }) => {
-        if (LinkFollowBox.sourceDoc && LinkFollowBox.linkDoc) {
-            const focus = (document: Doc) => { (LinkFollowBox._addDocTab || this.props.addDocTab)(document, "inTab"); SelectionManager.DeselectAll(); };
-            //let focus = (doc: Doc, maxLocation: string) => this.props.focus(docthis.props.focus(LinkFollowBox.destinationDoc, true, 1, () => this.props.addDocTab(doc, maxLocation));
-
-            DocumentManager.Instance.FollowLink(LinkFollowBox.linkDoc, LinkFollowBox.sourceDoc, focus, options && options.shouldZoom, false, undefined);
-        }
-    }
-
-    @undoBatch
-    openLinkTab = () => {
-        if (LinkFollowBox.destinationDoc) {
-            const fullScreenAlias = Doc.MakeAlias(LinkFollowBox.destinationDoc);
-            // this.prosp.addDocTab is empty -- use the link source's addDocTab 
-            (LinkFollowBox._addDocTab || this.props.addDocTab)(fullScreenAlias, "inTab");
-
-            this.highlightDoc();
-            SelectionManager.DeselectAll();
-        }
-    }
-
-    @undoBatch
-    openLinkColTab = (options: { context: Doc, shouldZoom: boolean }) => {
-        if (LinkFollowBox.destinationDoc) {
-            options.context = Doc.IsPrototype(options.context) ? Doc.MakeDelegate(options.context) : options.context;
-            if (NumCast(options.context._viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) {
-                const newPanX = NumCast(LinkFollowBox.destinationDoc.x) + NumCast(LinkFollowBox.destinationDoc._width) / 2;
-                const newPanY = NumCast(LinkFollowBox.destinationDoc.y) + NumCast(LinkFollowBox.destinationDoc._height) / 2;
-                options.context._panX = newPanX;
-                options.context._panY = newPanY;
-            }
-            (LinkFollowBox._addDocTab || this.props.addDocTab)(options.context, "inTab");
-            if (options.shouldZoom) this.jumpToLink({ shouldZoom: options.shouldZoom });
-
-            this.highlightDoc();
-            SelectionManager.DeselectAll();
-        }
-    }
-
-    @undoBatch
-    openLinkInPlace = (options: { shouldZoom: boolean }) => {
-
-        if (LinkFollowBox.destinationDoc && LinkFollowBox.sourceDoc) {
-            if (this.sourceView && this.sourceView.props.addDocument) {
-                const destViews = DocumentManager.Instance.getDocumentViews(LinkFollowBox.destinationDoc);
-                if (!destViews.find(dv => dv.props.ContainingCollectionView === this.sourceView!.props.ContainingCollectionView)) {
-                    const alias = Doc.MakeAlias(LinkFollowBox.destinationDoc);
-                    const y = NumCast(LinkFollowBox.sourceDoc.y);
-                    const x = NumCast(LinkFollowBox.sourceDoc.x);
-
-                    const width = NumCast(LinkFollowBox.sourceDoc._width);
-                    const height = NumCast(LinkFollowBox.sourceDoc._height);
-
-                    alias.x = x + width + 30;
-                    alias.y = y;
-                    alias._width = width;
-                    alias._height = height;
-
-                    this.sourceView.props.addDocument(alias);
-                }
-            }
-
-            this.jumpToLink({ shouldZoom: options.shouldZoom });
-
-            this.highlightDoc();
-            SelectionManager.DeselectAll();
-        }
-    }
-
-    //set this to be the default link behavior, can be any of the above
-    public defaultLinkBehavior: (options?: any) => void = this.jumpToLink;
-
-    @action
-    currentLinkBehavior = () => {
-        // this.resetPan();
-        if (LinkFollowBox.destinationDoc) {
-            if (this.selectedContextString === "") {
-                this.selectedContextString = "self";
-                this.selectedContext = LinkFollowBox.destinationDoc;
-            }
-            if (this.selectedOption === "") this.selectedOption = FollowOptions.NOZOOM;
-            const shouldZoom: boolean = this.selectedOption === FollowOptions.NOZOOM ? false : true;
-            const notOpenInContext: boolean = this.selectedContextString === "self" || this.selectedContextString === LinkFollowBox.destinationDoc[Id];
-
-            if (this.selectedMode === FollowModes.INPLACE) {
-                if (shouldZoom !== undefined) this.openLinkInPlace({ shouldZoom: shouldZoom });
-            }
-            else if (this.selectedMode === FollowModes.OPENFULL) {
-                if (notOpenInContext) this.openFullScreen();
-                else this.selectedContext && this.openColFullScreen({ context: this.selectedContext });
-            }
-            else if (this.selectedMode === FollowModes.OPENRIGHT) {
-                if (notOpenInContext) this.openLinkRight();
-                else this.selectedContext && this.openLinkColRight({ context: this.selectedContext, shouldZoom: shouldZoom });
-            }
-            else if (this.selectedMode === FollowModes.OPENTAB) {
-                if (notOpenInContext) this.openLinkTab();
-                else this.selectedContext && this.openLinkColTab({ context: this.selectedContext, shouldZoom: shouldZoom });
-            }
-            else if (this.selectedMode === FollowModes.PAN) {
-                this.jumpToLink({ shouldZoom: shouldZoom });
-            }
-            else return;
-        }
-    }
-
-    @action
-    handleModeChange = (e: React.ChangeEvent) => {
-        const target = e.target as HTMLInputElement;
-        this.selectedMode = target.value;
-        this.selectedContext = undefined;
-        this.selectedContextString = "";
-
-        this.shouldUseOnlyParentContext = (this.selectedMode === FollowModes.INPLACE || this.selectedMode === FollowModes.PAN);
-
-        if (this.shouldUseOnlyParentContext) {
-            if (this.sourceView && this.sourceView.props.ContainingCollectionDoc) {
-                this.selectedContext = this.sourceView.props.ContainingCollectionDoc;
-                this.selectedContextString = (StrCast(this.sourceView.props.ContainingCollectionDoc.title));
-            }
-        }
-    }
-
-    @action
-    handleOptionChange = (e: React.ChangeEvent) => {
-        const target = e.target as HTMLInputElement;
-        this.selectedOption = target.value;
-    }
-
-    @action
-    handleContextChange = (e: React.ChangeEvent) => {
-        const target = e.target as HTMLInputElement;
-        this.selectedContextString = target.value;
-        // selectedContext is updated in reaction
-        this.selectedOption = "";
-    }
-
-    @computed
-    get canOpenInPlace() {
-        if (this.sourceView && this.sourceView.props.ContainingCollectionDoc) {
-            const colDoc = this.sourceView.props.ContainingCollectionDoc;
-            if (colDoc._viewType === CollectionViewType.Freeform) return true;
-        }
-        return false;
-    }
-
-    @computed
-    get availableModes() {
-        return (
-            <div>
-                <label><input
-                    type="radio"
-                    name="mode"
-                    value={FollowModes.OPENRIGHT}
-                    checked={this.selectedMode === FollowModes.OPENRIGHT}
-                    onChange={this.handleModeChange}
-                    disabled={false} />
-                    {FollowModes.OPENRIGHT}
-                </label><br />
-                <label><input
-                    type="radio"
-                    name="mode"
-                    value={FollowModes.OPENTAB}
-                    checked={this.selectedMode === FollowModes.OPENTAB}
-                    onChange={this.handleModeChange}
-                    disabled={false} />
-                    {FollowModes.OPENTAB}
-                </label><br />
-                <label><input
-                    type="radio"
-                    name="mode"
-                    value={FollowModes.OPENFULL}
-                    checked={this.selectedMode === FollowModes.OPENFULL}
-                    onChange={this.handleModeChange}
-                    disabled={false} />
-                    {FollowModes.OPENFULL}
-                </label><br />
-                <label><input
-                    type="radio"
-                    name="mode"
-                    value={FollowModes.PAN}
-                    checked={this.selectedMode === FollowModes.PAN}
-                    onChange={this.handleModeChange}
-                    disabled={!this.canPan} />
-                    {FollowModes.PAN}
-                </label><br />
-                <label><input
-                    type="radio"
-                    name="mode"
-                    value={FollowModes.INPLACE}
-                    checked={this.selectedMode === FollowModes.INPLACE}
-                    onChange={this.handleModeChange}
-                    disabled={!this.canOpenInPlace} />
-                    {FollowModes.INPLACE}
-                </label><br />
-            </div>
-        );
-    }
-
-    @computed
-    get parentName() {
-        if (this.sourceView && this.sourceView.props.ContainingCollectionDoc) {
-            return this.sourceView.props.ContainingCollectionDoc.title;
-        }
-    }
-
-    @computed
-    get parentID(): string {
-        if (this.sourceView && this.sourceView.props.ContainingCollectionDoc) {
-            return StrCast(this.sourceView.props.ContainingCollectionDoc[Id]);
-        }
-        return "col";
-    }
-
-    @computed
-    get availableContexts() {
-        return (
-            this.shouldUseOnlyParentContext ?
-                <label><input
-                    type="radio" disabled={true}
-                    name="context"
-                    value={this.parentID}
-                    checked={true} />
-                    {this.parentName} (Parent Collection)
-                </label>
-                :
-                <div>
-                    <label><input
-                        type="radio" disabled={LinkFollowBox.linkDoc ? false : true}
-                        name="context"
-                        value={LinkFollowBox.destinationDoc ? StrCast(LinkFollowBox.destinationDoc[Id]) : "self"}
-                        checked={LinkFollowBox.destinationDoc ? this.selectedContextString === StrCast(LinkFollowBox.destinationDoc[Id]) || this.selectedContextString === "self" : true}
-                        onChange={this.handleContextChange} />
-                        Open Self
-                </label><br />
-                    {[...this._docs, ...this._otherDocs].map(doc => {
-                        if (doc && doc.target && doc.col.title !== "Recently Closed") {
-                            return <div key={doc.col[Id] + doc.target[Id]}><label key={doc.col[Id] + doc.target[Id]}>
-                                <input
-                                    type="radio" disabled={LinkFollowBox.linkDoc ? false : true}
-                                    name="context"
-                                    value={StrCast(doc.col[Id])}
-                                    checked={this.selectedContextString === StrCast(doc.col[Id])}
-                                    onChange={this.handleContextChange} />
-                                {doc.col.title}
-                            </label><br /></div>;
-                        }
-                    })}
-                </div>
-        );
-    }
-
-    @computed
-    get shouldShowZoom(): boolean {
-        if (this.selectedMode === FollowModes.OPENFULL) return false;
-        if (this.shouldUseOnlyParentContext) return true;
-        if (LinkFollowBox.destinationDoc ? this.selectedContextString === LinkFollowBox.destinationDoc[Id] : "self") return false;
-
-        let contextMatch: boolean = false;
-        if (this.selectedContextAliases) {
-            this.selectedContextAliases.forEach(alias => {
-                if (alias._viewType === CollectionViewType.Freeform) contextMatch = true;
-            });
-        }
-        if (contextMatch) return true;
-
-        return false;
-    }
-
-    @computed
-    get availableOptions() {
-        if (LinkFollowBox.destinationDoc) {
-            return (
-                this.shouldShowZoom ?
-                    <div>
-                        <label><input
-                            type="radio"
-                            name="option"
-                            value={FollowOptions.ZOOM}
-                            checked={this.selectedOption === FollowOptions.ZOOM}
-                            onChange={this.handleOptionChange}
-                            disabled={false} />
-                            {FollowOptions.ZOOM}
-                        </label><br />
-                        <label><input
-                            type="radio"
-                            name="option"
-                            value={FollowOptions.NOZOOM}
-                            checked={this.selectedOption === FollowOptions.NOZOOM}
-                            onChange={this.handleOptionChange}
-                            disabled={false} />
-                            {FollowOptions.NOZOOM}
-                        </label><br />
-                    </div>
-                    :
-                    <div>No Available Options</div>
-            );
-        }
-        return null;
-    }
-
-    render() {
-        return (
-            <div className="linkFollowBox-main" style={{ height: NumCast(this.props.Document._height), width: NumCast(this.props.Document._width) }}>
-                <div className="linkFollowBox-header">
-                    <div className="topHeader">
-                        {LinkFollowBox.linkDoc ? "Link Title: " + StrCast(LinkFollowBox.linkDoc.title) : "No Link Selected"}
-                        <div onClick={() => this.props.Document.isMinimized = true} className="closeDocument"><FontAwesomeIcon icon={faTimes} size="lg" /></div>
-                    </div>
-                    <div className=" direction-indicator">{LinkFollowBox.linkDoc ?
-                        LinkFollowBox.sourceDoc && LinkFollowBox.destinationDoc ? "Source: " + StrCast(LinkFollowBox.sourceDoc.title) + ", Destination: " + StrCast(LinkFollowBox.destinationDoc.title)
-                            : "" : ""}</div>
-                </div>
-                <div className="linkFollowBox-content" style={{ height: NumCast(this.props.Document._height) - 110 }}>
-                    <div className="linkFollowBox-item">
-                        <div className="linkFollowBox-item title">Mode</div>
-                        <div className="linkFollowBox-itemContent">
-                            {LinkFollowBox.linkDoc ? this.availableModes : "Please select a link to view modes"}
-                        </div>
-                    </div>
-                    <div className="linkFollowBox-item">
-                        <div className="linkFollowBox-item title">Context</div>
-                        <div className="linkFollowBox-itemContent">
-                            {this.selectedMode !== "" ? this.availableContexts : "Please select a mode to view contexts"}
-                        </div>
-                    </div>
-                    <div className="linkFollowBox-item">
-                        <div className="linkFollowBox-item title">Options</div>
-                        <div className="linkFollowBox-itemContent">
-                            {this.selectedContextString !== "" ? this.availableOptions : "Please select a context to view options"}
-                        </div>
-                    </div>
-                </div>
-                <div className="linkFollowBox-footer">
-                    <button
-                        onClick={this.resetVars}>
-                        Clear Link
-                    </button>
-                    <div style={{ width: 20 }}></div>
-                    <button
-                        onClick={this.currentLinkBehavior}
-                        disabled={(LinkFollowBox.linkDoc) ? false : true}>
-                        Follow Link
-                    </button>
-                </div>
-            </div>
-        );
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 376afa64b..5fd6e4630 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -8,7 +8,6 @@ import { Cast, StrCast } from '../../../new_fields/Types';
 import { DragManager } from '../../util/DragManager';
 import { LinkManager } from '../../util/LinkManager';
 import { ContextMenu } from '../ContextMenu';
-import { LinkFollowBox } from './LinkFollowBox';
 import './LinkMenuItem.scss';
 import React = require("react");
 import { DocumentManager } from '../../util/DocumentManager';
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 73a53f5cc..bfda13eb3 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -9,7 +9,6 @@ import { CollectionDockingView } from "../collections/CollectionDockingView";
 import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
 import { CollectionSchemaView } from "../collections/CollectionSchemaView";
 import { CollectionView } from "../collections/CollectionView";
-import { LinkFollowBox } from "../linking/LinkFollowBox";
 import { YoutubeBox } from "./../../apis/youtube/YoutubeBox";
 import { AudioBox } from "./AudioBox";
 import { ButtonBox } from "./ButtonBox";
@@ -108,7 +107,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
                 components={{
                     FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, ButtonBox, SliderBox, FieldView,
                     CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
-                    PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox, LinkFollowBox, PresElementBox, QueryBox,
+                    PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox, PresElementBox, QueryBox,
                     ColorBox, DashWebRTCVideo, DocuLinkBox, InkingStroke, DocumentBox, LinkBox
                 }}
                 bindings={this.CreateBindings()}
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 32439757c..8fe2257fc 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -265,8 +265,6 @@ export class CurrentUserUtils {
     // sets up the default set of documents to be shown in the Overlay layer
     static setupOverlays(doc: Doc) {
         doc.overlays = Docs.Create.FreeformDocument([], { title: "Overlays", backgroundColor: "#aca3a6" });
-        doc.linkFollowBox = Docs.Create.LinkFollowBoxDocument({ x: 250, y: 20, _width: 500, _height: 370, title: "Link Follower" });
-        Doc.AddDocToList(doc.overlays as Doc, "data", doc.linkFollowBox as Doc);
     }
 
     // the initial presentation Doc to use
-- 
cgit v1.2.3-70-g09d2


From 8190b6557065828e3a5e7a6505c0963a433e27d1 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 27 Feb 2020 17:05:39 -0500
Subject: adding colors to schema view will update the enumerated colors used
 by text boxes in freeformview.

---
 .../views/collections/CollectionStackingView.tsx     |  5 ++++-
 .../CollectionStackingViewFieldColumn.tsx            |  4 ++--
 src/client/views/nodes/PresBox.tsx                   |  2 --
 src/client/views/pdf/Annotation.tsx                  |  2 +-
 src/new_fields/Doc.ts                                | 20 ++++++++++++++++----
 5 files changed, 23 insertions(+), 10 deletions(-)

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index a1cc21319..4495e8248 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -24,6 +24,7 @@ import "./CollectionStackingView.scss";
 import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn";
 import { CollectionSubView } from "./CollectionSubView";
 import { CollectionViewType } from "./CollectionView";
+import { Docs } from "../../documents/Documents";
 
 @observer
 export class CollectionStackingView extends CollectionSubView(doc => doc) {
@@ -348,7 +349,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @action
     addGroup = (value: string) => {
         if (value && this.sectionHeaders) {
-            this.sectionHeaders.push(new SchemaHeaderField(value));
+            const schemaHdrField = new SchemaHeaderField(value);
+            this.sectionHeaders.push(schemaHdrField);
+            Doc.addEnumerationToTextField(undefined, this.sectionFilter, [Docs.Create.TextDocument(value, { title: value, _backgroundColor: schemaHdrField.color })]);
             return true;
         }
         return false;
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 8c23ecd49..058733cc9 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -68,10 +68,10 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
             const key = StrCast(this.props.parent.props.Document.sectionFilter);
             const castedValue = this.getValue(this._heading);
             if (castedValue) {
-                de.complete.docDragData.droppedDocuments.forEach(d => d[key] = castedValue);
+                de.complete.docDragData.droppedDocuments.forEach(d => Doc.SetInPlace(d, key, castedValue, false));
             }
             else {
-                de.complete.docDragData.droppedDocuments.forEach(d => d[key] = undefined);
+                de.complete.docDragData.droppedDocuments.forEach(d => Doc.SetInPlace(d, key, undefined, false));
             }
             this.props.parent.onInternalDrop(e, de);
             e.stopPropagation();
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 791ed5ef1..4180ee255 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -10,7 +10,6 @@ import { listSpec } from "../../../new_fields/Schema";
 import { BoolCast, Cast, FieldValue, NumCast } from "../../../new_fields/Types";
 import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
 import { returnFalse } from "../../../Utils";
-import { Docs } from "../../documents/Documents";
 import { DocumentManager } from "../../util/DocumentManager";
 import { undoBatch } from "../../util/UndoManager";
 import { CollectionDockingView } from "../collections/CollectionDockingView";
@@ -20,7 +19,6 @@ import { ContextMenuProps } from "../ContextMenuItem";
 import { InkingControl } from "../InkingControl";
 import { FieldView, FieldViewProps } from './FieldView';
 import "./PresBox.scss";
-import { PrefetchProxy } from "../../../new_fields/Proxy";
 
 library.add(faArrowLeft);
 library.add(faArrowRight);
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 58823c93d..d23c81065 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -1,7 +1,7 @@
 import React = require("react");
 import { action, IReactionDisposer, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, DocListCast, HeightSym, WidthSym, Opt, DocListCastAsync } from "../../../new_fields/Doc";
+import { Doc, DocListCast, HeightSym, WidthSym } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
 import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 8ea347ec3..d364bfe28 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -858,16 +858,28 @@ export namespace Doc {
         Doc.addEnumerationToTextField(doc, enumeratedFieldKey, enumeratedDocs);
     }
 
-    export function addEnumerationToTextField(doc: Doc, enumeratedFieldKey: string, enumeratedDocs: Doc[]) {
+    export async function getEnumerationTextField(enumeratedFieldKey: string) {
+        return (await DocServer.GetRefField(enumeratedFieldKey)) as Doc;
+    }
+
+    export function addEnumerationToTextField(doc: Opt<Doc>, enumeratedFieldKey: string, enumeratedDocs: Doc[]) {
         DocServer.GetRefField(enumeratedFieldKey).then(optionsCollection => {
             if (!(optionsCollection instanceof Doc)) {
                 optionsCollection = Docs.Create.StackingDocument([], { title: `${enumeratedFieldKey} field set` }, enumeratedFieldKey);
                 Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc);
             }
             const options = optionsCollection as Doc;
-            doc.backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey})?._backgroundColor || "white"`, undefined, { options });
-            doc.color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey}).color || "black"`, undefined, { options });
-            enumeratedDocs.map(enumeratedDoc => !DocListCast(options.data).find(d => d.title === enumeratedDoc.title) && Doc.AddDocToList(options, "data", enumeratedDoc));
+            doc && (doc.backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey})?._backgroundColor || "white"`, undefined, { options }));
+            doc && (doc.color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey}).color || "black"`, undefined, { options }));
+            enumeratedDocs.map(enumeratedDoc => {
+                const found = DocListCast(options.data).find(d => d.title === enumeratedDoc.title);
+                if (found) {
+                    found._backgroundColor = enumeratedDoc._backgroundColor || found._backgroundColor;
+                    found._color = enumeratedDoc._color || found._color;
+                } else {
+                    Doc.AddDocToList(options, "data", enumeratedDoc);
+                }
+            });
         });
     }
 }
-- 
cgit v1.2.3-70-g09d2


From 44a521a2b333913ee83bd325b84d1dbd03339398 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 27 Feb 2020 22:05:12 -0500
Subject: schema view & Stacking view code cleanup and minor ui fixes

---
 .../views/collections/CollectionSchemaView.tsx     | 43 ++---------
 .../views/collections/CollectionStackingView.scss  | 18 ++++-
 .../views/collections/CollectionStackingView.tsx   | 30 +++-----
 .../CollectionStackingViewFieldColumn.tsx          | 89 ++++++----------------
 src/new_fields/Doc.ts                              |  4 +-
 5 files changed, 58 insertions(+), 126 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 9486d195a..6eeceb552 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -28,6 +28,7 @@ import "./CollectionSchemaView.scss";
 import { CollectionSubView } from "./CollectionSubView";
 import { CollectionView } from "./CollectionView";
 import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
+import { setupMoveUpEvents, emptyFunction } from "../../../Utils";
 
 library.add(faCog, faPlus, faSortUp, faSortDown);
 library.add(faTable);
@@ -43,8 +44,8 @@ export enum ColumnType {
 // 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],
+    ["x", ColumnType.Number], ["y", ColumnType.Number], ["_width", ColumnType.Number], ["_height", ColumnType.Number],
+    ["_nativeWidth", ColumnType.Number], ["_nativeHeight", ColumnType.Number], ["isPrototype", ColumnType.Boolean],
     ["page", ColumnType.Number], ["curPage", ColumnType.Number], ["currentTimecode", ColumnType.Number], ["zIndex", ColumnType.Number]
 ]);
 
@@ -54,9 +55,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
     private _startPreviewWidth = 0;
     private DIVIDER_WIDTH = 4;
 
-    @observable previewScript: string = "";
     @observable previewDoc: Doc | undefined = undefined;
-    @observable private _node: HTMLDivElement | null = null;
     @observable private _focusedTable: Doc = this.props.Document;
 
     @computed get previewWidth() { return () => NumCast(this.props.Document.schemaPreviewWidth); }
@@ -75,9 +74,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
 
     @action setPreviewDoc = (doc: Doc) => this.previewDoc = doc;
 
-    @undoBatch
-    @action setPreviewScript = (script: string) => this.previewScript = script
-
     //toggles preview side-panel of schema
     @action
     toggleExpander = () => {
@@ -86,27 +82,17 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
 
     onDividerDown = (e: React.PointerEvent) => {
         this._startPreviewWidth = this.previewWidth();
-        e.stopPropagation();
-        e.preventDefault();
-        document.addEventListener("pointermove", this.onDividerMove);
-        document.addEventListener('pointerup', this.onDividerUp);
+        setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, action(() => this.toggleExpander()));
     }
     @action
-    onDividerMove = (e: PointerEvent): void => {
+    onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => {
         const nativeWidth = this._mainCont!.getBoundingClientRect();
         const minWidth = 40;
         const maxWidth = 1000;
         const movedWidth = this.props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0];
         const width = movedWidth < minWidth ? minWidth : movedWidth > maxWidth ? maxWidth : movedWidth;
         this.props.Document.schemaPreviewWidth = width;
-    }
-    @action
-    onDividerUp = (e: PointerEvent): void => {
-        document.removeEventListener("pointermove", this.onDividerMove);
-        document.removeEventListener('pointerup', this.onDividerUp);
-        if (this._startPreviewWidth === this.previewWidth()) {
-            this.toggleExpander();
-        }
+        return false;
     }
 
     onPointerDown = (e: React.PointerEvent): void => {
@@ -119,9 +105,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
     }
 
     @computed
-    get previewDocument(): Doc | undefined {
-        return this.previewDoc ? (this.previewScript && this.previewScript !== "this" ? FieldValue(Cast(this.previewDoc[this.previewScript], Doc)) : this.previewDoc) : undefined;
-    }
+    get previewDocument(): Doc | undefined { return this.previewDoc; }
 
     getPreviewTransform = (): Transform => {
         return this.props.ScreenToLocalTransform().translate(- this.borderWidth - this.DIVIDER_WIDTH - this.tableWidth, - this.borderWidth);
@@ -477,8 +461,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
 
     @undoBatch
     createRow = () => {
-        const newDoc = Docs.Create.TextDocument("", { title: "", _width: 100, _height: 30 });
-        this.props.addDocument(newDoc);
+        this.props.addDocument(Docs.Create.TextDocument("", { title: "", _width: 100, _height: 30 }));
     }
 
     @undoBatch
@@ -559,16 +542,6 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
             columns[index] = columnField;
             this.columns = columns;
         }
-
-        // const typesDoc = FieldValue(Cast(this.props.Document.schemaColumnTypes, Doc));
-        // if (!typesDoc) {
-        //     let newTypesDoc = new Doc();
-        //     newTypesDoc[key] = type;
-        //     this.props.Document.schemaColumnTypes = newTypesDoc;
-        //     return;
-        // } else {
-        //     typesDoc[key] = type;
-        // }
     }
 
     @undoBatch
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 293dc5414..8e3919532 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -160,9 +160,7 @@
     }
     .collectionStackingView-sectionHeader {
         text-align: center;
-        margin-left: 2px;
-        margin-right: 2px;
-        margin-top: 10px;
+        margin: auto;
         background: $main-accent;
         // overflow: hidden; overflow is visible so the color menu isn't hidden -ftong
 
@@ -214,6 +212,7 @@
             left: 0;
             top: 0;
             height: 100%;
+            display: none;
 
             [class*="css"] {
                 max-width: 102px;
@@ -251,6 +250,7 @@
             right: 0;
             top: 0;
             height: 100%;
+            display: none;
 
             [class*="css"] {
                 max-width: 102px;
@@ -285,6 +285,18 @@
             right: 25px;
             top: 0;
             height: 100%;
+            display: none;
+        }
+    }
+    .collectionStackingView-sectionHeader:hover {
+        .collectionStackingView-sectionColor {
+            display:unset;
+        }
+        .collectionStackingView-sectionOptions {
+            display:unset;
+        }
+        .collectionStackingView-sectionDelete {
+            display:unset;
         }
     }
 
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 4495e8248..d1f45af90 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -11,7 +11,7 @@ import { listSpec } from "../../../new_fields/Schema";
 import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types";
 import { TraceMobx } from "../../../new_fields/util";
-import { Utils } from "../../../Utils";
+import { Utils, setupMoveUpEvents, emptyFunction } from "../../../Utils";
 import { DragManager } from "../../util/DragManager";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
@@ -61,7 +61,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             const dxf = () => this.getDocTransform(d, dref.current!);
             this._docXfs.push({ dxf: dxf, width: width, height: height });
             const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap);
-            const style = this.isStackingView ? { width: width(), marginTop: i === 0 ? 0 : this.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` };
+            const style = this.isStackingView ? { width: width(), marginTop: this.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` };
             return <div className={`collectionStackingView-${this.isStackingView ? "columnDoc" : "masonryDoc"}`} key={d[Id]} ref={dref} style={style} >
                 {this.getDisplayDoc(d, this.props.DataDoc, dxf, width)}
             </div>;
@@ -79,8 +79,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             setTimeout(() => this.props.Document.sectionHeaders = new List<SchemaHeaderField>(), 0);
             return new Map<SchemaHeaderField, Doc[]>();
         }
-        const sectionHeaders = this.sectionHeaders;
+        const sectionHeaders: SchemaHeaderField[] = Array.from(this.sectionHeaders);
         const fields = new Map<SchemaHeaderField, Doc[]>(sectionHeaders.map(sh => [sh, []] as [SchemaHeaderField, []]));
+        let changed = false;
         this.filteredChildren.map(d => {
             const sectionValue = (d[this.sectionFilter] ? d[this.sectionFilter] : `NO ${this.sectionFilter.toUpperCase()} VALUE`) as object;
             // the next five lines ensures that floating point rounding errors don't create more than one section -syip
@@ -96,8 +97,10 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                 const newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `NO ${this.sectionFilter.toUpperCase()} VALUE`);
                 fields.set(newSchemaHeader, [d]);
                 sectionHeaders.push(newSchemaHeader);
+                changed = true;
             }
         });
+        changed && setTimeout(action(() => { if (this.sectionHeaders) { this.sectionHeaders.length = 0; this.sectionHeaders.push(...sectionHeaders); } }), 0);
         return fields;
     }
 
@@ -204,26 +207,13 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
 
     columnDividerDown = (e: React.PointerEvent) => {
-        e.stopPropagation();
-        e.preventDefault();
         runInAction(() => this._cursor = "grabbing");
-        document.addEventListener("pointermove", this.onDividerMove);
-        document.addEventListener('pointerup', this.onDividerUp);
-        this._columnStart = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0];
+        setupMoveUpEvents(this, e, this.onDividerMove, action(() => this._cursor = "grab"), emptyFunction);
     }
     @action
-    onDividerMove = (e: PointerEvent): void => {
-        const dragPos = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0];
-        const delta = dragPos - this._columnStart;
-        this._columnStart = dragPos;
-        this.layoutDoc.columnWidth = Math.max(10, this.columnWidth + delta);
-    }
-
-    @action
-    onDividerUp = (e: PointerEvent): void => {
-        runInAction(() => this._cursor = "grab");
-        document.removeEventListener("pointermove", this.onDividerMove);
-        document.removeEventListener('pointerup', this.onDividerUp);
+    onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => {
+        this.layoutDoc.columnWidth = Math.max(10, this.columnWidth + delta[0]);
+        return false;
     }
 
     @computed get columnDragger() {
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 058733cc9..17011698f 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -20,7 +20,10 @@ import { ContextMenu } from "../ContextMenu";
 import { ContextMenuProps } from "../ContextMenuItem";
 import { EditableView } from "../EditableView";
 import { CollectionStackingView } from "./CollectionStackingView";
+import { setupMoveUpEvents, emptyFunction } from "../../../Utils";
 import "./CollectionStackingView.scss";
+import { listSpec } from "../../../new_fields/Schema";
+import { Schema } from "prosemirror-model";
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -42,20 +45,15 @@ interface CSVFieldColumnProps {
 @observer
 export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldColumnProps> {
     @observable private _background = "inherit";
-    @observable private _createAliasSelected: boolean = false;
 
-    private _dropRef: HTMLDivElement | null = null;
     private dropDisposer?: DragManager.DragDropDisposer;
     private _headerRef: React.RefObject<HTMLDivElement> = React.createRef();
-    private _startDragPosition: { x: number, y: number } = { x: 0, y: 0 };
-    private _sensitivity: number = 16;
 
     @observable _heading = this.props.headingObject ? this.props.headingObject.heading : this.props.heading;
     @observable _color = this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
 
     createColumnDropRef = (ele: HTMLDivElement | null) => {
-        this._dropRef = ele;
-        this.dropDisposer && this.dropDisposer();
+        this.dropDisposer?.();
         if (ele) {
             this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this));
         }
@@ -63,16 +61,10 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
 
     @undoBatch
     columnDrop = action((e: Event, de: DragManager.DropEvent) => {
-        this._createAliasSelected = false;
         if (de.complete.docDragData) {
             const key = StrCast(this.props.parent.props.Document.sectionFilter);
             const castedValue = this.getValue(this._heading);
-            if (castedValue) {
-                de.complete.docDragData.droppedDocuments.forEach(d => Doc.SetInPlace(d, key, castedValue, false));
-            }
-            else {
-                de.complete.docDragData.droppedDocuments.forEach(d => Doc.SetInPlace(d, key, undefined, false));
-            }
+            de.complete.docDragData.droppedDocuments.forEach(d => Doc.SetInPlace(d, key, castedValue, false));
             this.props.parent.onInternalDrop(e, de);
             e.stopPropagation();
         }
@@ -93,7 +85,6 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
 
     @action
     headingChanged = (value: string, shiftDown?: boolean) => {
-        this._createAliasSelected = false;
         const key = StrCast(this.props.parent.props.Document.sectionFilter);
         const castedValue = this.getValue(value);
         if (castedValue) {
@@ -114,7 +105,6 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
 
     @action
     changeColumnColor = (color: string) => {
-        this._createAliasSelected = false;
         if (this.props.headingObject) {
             this.props.headingObject.setColor(color);
             this._color = color;
@@ -124,22 +114,18 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
     @action
     pointerEntered = () => {
         if (SelectionManager.GetIsDragging()) {
-            this._createAliasSelected = false;
             this._background = "#b4b4b4";
         }
     }
 
     @action
     pointerLeave = () => {
-        this._createAliasSelected = false;
         this._background = "inherit";
-        document.removeEventListener("pointermove", this.startDrag);
     }
 
     @action
     addDocument = (value: string, shiftDown?: boolean) => {
         if (!value) return false;
-        this._createAliasSelected = false;
         const key = StrCast(this.props.parent.props.Document.sectionFilter);
         const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, title: value, _autoHeight: true });
         newDoc[key] = this.getValue(this.props.heading);
@@ -151,7 +137,6 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
 
     @action
     deleteColumn = () => {
-        this._createAliasSelected = false;
         const key = StrCast(this.props.parent.props.Document.sectionFilter);
         this.props.docList.forEach(d => d[key] = undefined);
         if (this.props.parent.sectionHeaders && this.props.headingObject) {
@@ -162,7 +147,6 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
 
     @action
     collapseSection = () => {
-        this._createAliasSelected = false;
         if (this.props.headingObject) {
             this._headingsHack++;
             this.props.headingObject.setCollapsed(!this.props.headingObject.collapsed);
@@ -170,46 +154,23 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         }
     }
 
-    startDrag = (e: PointerEvent) => {
-        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) {
-            const alias = Doc.MakeAlias(this.props.parent.props.Document);
-            const key = StrCast(this.props.parent.props.Document.sectionFilter);
-            let value = this.getValue(this._heading);
-            value = typeof value === "string" ? `"${value}"` : value;
-            alias.viewSpecScript = ScriptField.MakeFunction(`doc.${key} === ${value}`, { doc: Doc.name });
-            if (alias.viewSpecScript) {
-                DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY);
-            }
-
-            e.stopPropagation();
-            document.removeEventListener("pointermove", this.startDrag);
-            document.removeEventListener("pointerup", this.pointerUp);
-        }
-    }
-
-    pointerUp = (e: PointerEvent) => {
-        e.stopPropagation();
-        e.preventDefault();
-
-        document.removeEventListener("pointermove", this.startDrag);
-        document.removeEventListener("pointerup", this.pointerUp);
-    }
-
     headerDown = (e: React.PointerEvent<HTMLDivElement>) => {
-        e.stopPropagation();
-        e.preventDefault();
-
-        const [dx, dy] = this.props.screenToLocalTransform().transformDirection(e.clientX, e.clientY);
-        this._startDragPosition = { x: dx, y: dy };
+        setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction);
+    }
 
-        if (this._createAliasSelected) {
-            document.removeEventListener("pointermove", this.startDrag);
-            document.addEventListener("pointermove", this.startDrag);
-            document.removeEventListener("pointerup", this.pointerUp);
-            document.addEventListener("pointerup", this.pointerUp);
+    startDrag = (e: PointerEvent, down: number[], delta: number[]) => {
+        const alias = Doc.MakeAlias(this.props.parent.props.Document);
+        alias._width = this.props.parent.props.PanelWidth() / (Cast(this.props.parent.props.Document.schemaColumns, listSpec(SchemaHeaderField))?.length || 1);
+        alias.sectionFilter = undefined;
+        const key = StrCast(this.props.parent.props.Document.sectionFilter);
+        let value = this.getValue(this._heading);
+        value = typeof value === "string" ? `"${value}"` : value;
+        alias.viewSpecScript = ScriptField.MakeFunction(`doc.${key} === ${value}`, { doc: Doc.name });
+        if (alias.viewSpecScript) {
+            DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY);
+            return true;
         }
-        runInAction(() => this._createAliasSelected = false);
+        return false;
     }
 
     renderColorPicker = () => {
@@ -242,17 +203,11 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         );
     }
 
-    @action
-    toggleAlias = () => {
-        this._createAliasSelected = true;
-    }
-
     renderMenu = () => {
-        const selected = this._createAliasSelected;
         return (
             <div className="collectionStackingView-optionPicker">
                 <div className="optionOptions">
-                    <div className={"optionPicker" + (selected === true ? " active" : "")} onClick={this.toggleAlias}>Create Alias</div>
+                    <div className={"optionPicker" + (true ? " active" : "")} onClick={action(() => { })}>Add options here</div>
                 </div>
             </div >
         );
@@ -328,6 +283,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         const heading = this._heading;
         const style = this.props.parent;
         const singleColumn = style.isStackingView;
+        const columnYMargin = this.props.headingObject ? 0 : NumCast(this.props.parent.props.Document._yMargin);
         const uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx);
         const evContents = heading ? heading : this.props.type && this.props.type === "number" ? "0" : `NO ${key.toUpperCase()} VALUE`;
         const headerEditableViewProps = {
@@ -352,6 +308,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         const headingView = this.props.headingObject ?
             <div key={heading} className="collectionStackingView-sectionHeader" ref={this._headerRef}
                 style={{
+                    marginTop: NumCast(this.props.parent.props.Document._yMargin),
                     width: (style.columnWidth) /
                         ((uniqueHeadings.length +
                             ((this.props.parent.props.Document._chromeStatus !== 'view-mode' && this.props.parent.props.Document._chromeStatus !== 'disabled') ? 1 : 0)) || 1)
@@ -404,7 +361,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
                         <div>
                             <div key={`${heading}-stack`} className={`collectionStackingView-masonry${singleColumn ? "Single" : "Grid"}`}
                                 style={{
-                                    padding: singleColumn ? `${style.yMargin}px ${0}px ${style.yMargin}px ${0}px` : `${style.yMargin}px ${0}px`,
+                                    padding: singleColumn ? `${columnYMargin}px ${0}px ${style.yMargin}px ${0}px` : `${columnYMargin}px ${0}px`,
                                     margin: "auto",
                                     width: "max-content", //singleColumn ? undefined : `${cols * (style.columnWidth + style.gridGap) + 2 * style.xMargin - style.gridGap}px`,
                                     height: 'max-content',
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index d364bfe28..ba8e21100 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -869,8 +869,8 @@ export namespace Doc {
                 Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc);
             }
             const options = optionsCollection as Doc;
-            doc && (doc.backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey})?._backgroundColor || "white"`, undefined, { options }));
-            doc && (doc.color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey}).color || "black"`, undefined, { options }));
+            doc && (Doc.GetProto(doc).backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey})?._backgroundColor || "white"`, undefined, { options }));
+            doc && (Doc.GetProto(doc).color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey}).color || "black"`, undefined, { options }));
             enumeratedDocs.map(enumeratedDoc => {
                 const found = DocListCast(options.data).find(d => d.title === enumeratedDoc.title);
                 if (found) {
-- 
cgit v1.2.3-70-g09d2


From d4fd33ea337b1136344b73b92e9d5494ff94f090 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 3 Mar 2020 10:49:22 -0500
Subject: fixes to allow navigation from hashtag tag to pivot/schema/stacking
 views

---
 src/client/documents/Documents.ts                  |  2 +-
 src/client/util/RichTextRules.ts                   | 10 +++++
 src/client/util/RichTextSchema.tsx                 | 52 +++++++++++++++-------
 .../collections/CollectionMasonryViewFieldRow.tsx  | 12 ++---
 .../views/collections/CollectionStackingView.tsx   | 30 ++++++-------
 .../CollectionStackingViewFieldColumn.tsx          | 15 +++----
 .../views/collections/CollectionViewChromes.scss   | 16 +++----
 .../views/collections/CollectionViewChromes.tsx    | 20 ++++-----
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 24 +++++-----
 .../authentication/models/current_user_utils.ts    |  2 +-
 10 files changed, 105 insertions(+), 78 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 4df90ceb8..49e7520f2 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -122,7 +122,7 @@ export interface DocumentOptions {
     displayTimecode?: number; // the time that a document should be displayed (e.g., time an annotation should be displayed on a video)
     borderRounding?: string;
     boxShadow?: string;
-    sectionFilter?: string; // field key used to determine headings for sections in stacking and masonry views
+    _pivotField?: string; // field key used to determine headings for sections in stacking, masonry, pivot views
     schemaColumns?: List<SchemaHeaderField>;
     dockingConfig?: string;
     annotationOn?: Doc;
diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts
index af3b1a81e..70a1a5154 100644
--- a/src/client/util/RichTextRules.ts
+++ b/src/client/util/RichTextRules.ts
@@ -100,6 +100,16 @@ export class RichTextRules {
                     const fieldView = state.schema.nodes.dashField.create({ fieldKey, docid });
                     return state.tr.deleteRange(start, end).insert(start, fieldView);
                 }),
+            // create an inline view of a tag stored under the '#' field
+            new InputRule(
+                new RegExp(/#([a-zA-Z_\-0-9]+)\s$/),
+                (state, match, start, end) => {
+                    const tag = match[1];
+                    if (!tag) return state.tr;
+                    this.Document[DataSym]["#"] = tag;
+                    const fieldView = state.schema.nodes.dashField.create({ fieldKey: "#" });
+                    return state.tr.deleteRange(start, end).insert(start, fieldView);
+                }),
             // create an inline view of a document {{ <layoutKey> : <Doc> }}  // {{:Doc}} => show default view of document   {{<layout>}} => show layout for this doc   {{<layout> : Doc}} => show layout for another doc
             new InputRule(
                 new RegExp(/\{\{([a-zA-Z_ \-0-9]*)(:[a-zA-Z_ \-0-9]+)?\}\}$/),
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index b2ee7320a..c67b42766 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -25,7 +25,11 @@ import { CollectionSchemaBooleanCell } from "../views/collections/CollectionSche
 import { ContextMenu } from "../views/ContextMenu";
 import { ContextMenuProps } from "../views/ContextMenuItem";
 import { Docs } from "../documents/Documents";
-import { CollectionView } from "../views/collections/CollectionView";
+import { CollectionView, CollectionViewType } from "../views/collections/CollectionView";
+import { toBlob } from "html-to-image";
+import { listSpec } from "../../new_fields/Schema";
+import { List } from "../../new_fields/List";
+import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField";
 
 const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"],
     preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0];
@@ -880,7 +884,7 @@ export class DashFieldView {
         this._fieldSpan.contentEditable = "true";
         this._fieldSpan.style.position = "relative";
         this._fieldSpan.style.display = "inline-block";
-        this._fieldSpan.style.minWidth = "50px";
+        this._fieldSpan.style.minWidth = "5px";
         this._fieldSpan.style.backgroundColor = "rgba(155, 155, 155, 0.24)";
         this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); };
         this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); };
@@ -893,6 +897,21 @@ export class DashFieldView {
                 }, icon: "expand-arrows-alt"
             });
         };
+        this._fieldSpan.onblur = function (e: any) {
+            let newText = self._fieldSpan.innerText.startsWith(":=") ? ":=-computed-" : self._fieldSpan.innerText;
+            // look for a document whose id === the fieldKey being displayed.  If there's a match, then that document
+            // holds the different enumerated values for the field in the titles of its collected documents.
+            // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down.
+
+            // alternatively, if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key
+            DocServer.GetRefField(node.attrs.fieldKey).then(options => {
+                (options instanceof Doc) && DocListCast(options.data).forEach(opt => StrCast(opt.title).startsWith(newText) && (newText = StrCast(opt.title)));
+                self._fieldSpan.innerHTML = self._dashDoc![self._fieldKey] = newText;
+                if (newText.startsWith(":=") && self._dashDoc && e.data === null && !e.inputType.includes("delete")) {
+                    Doc.Layout(tbox.props.Document)[self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(2));
+                }
+            });
+        }
 
         const setDashDoc = (doc: Doc) => {
             self._dashDoc = doc;
@@ -916,19 +935,7 @@ export class DashFieldView {
                 if (e.ctrlKey) {
                     Doc.addEnumerationToTextField(self._textBoxDoc, node.attrs.fieldKey, [Docs.Create.TextDocument(self._fieldSpan.innerText, { title: self._fieldSpan.innerText })]);
                 }
-                let newText = self._fieldSpan.innerText.startsWith(":=") ? ":=-computed-" : self._fieldSpan.innerText;
-                // look for a document whose id === the fieldKey being displayed.  If there's a match, then that document
-                // holds the different enumerated values for the field in the titles of its collected documents.
-                // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down.
-
-                // alternatively, if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key
-                DocServer.GetRefField(node.attrs.fieldKey).then(options => {
-                    (options instanceof Doc) && DocListCast(options.data).forEach(opt => StrCast(opt.title).startsWith(newText) && (newText = StrCast(opt.title)));
-                    self._fieldSpan.innerHTML = self._dashDoc![self._fieldKey] = newText;
-                    if (newText.startsWith(":=") && self._dashDoc && e.data === null && !e.inputType.includes("delete")) {
-                        Doc.Layout(tbox.props.Document)[self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(2));
-                    }
-                });
+                self._fieldSpan.onblur?.(undefined as any);
             }
         };
 
@@ -937,6 +944,21 @@ export class DashFieldView {
         this._labelSpan.style.display = "inline";
         this._labelSpan.style.fontWeight = "bold";
         this._labelSpan.style.fontSize = "larger";
+        this._labelSpan.onpointerdown = function (e: any) {
+            e.stopPropagation();
+            if (tbox.props.ContainingCollectionDoc) {
+                const alias = Doc.MakeAlias(tbox.props.ContainingCollectionDoc);
+                alias.viewType = CollectionViewType.Time;
+                let list = Cast(alias.schemaColumns, listSpec(SchemaHeaderField));
+                if (!list) {
+                    alias.schemaColumns = list = new List<SchemaHeaderField>();
+                }
+                list.map(c => c.heading).indexOf("#") === -1 && list.push(new SchemaHeaderField("#", "#f1efeb"));
+                list.map(c => c.heading).indexOf("text") === -1 && list.push(new SchemaHeaderField("text", "#f1efeb"));
+                alias._pivotField = "#";
+                tbox.props.addDocTab(alias, "onRight");
+            }
+        }
         this._labelSpan.innerHTML = `${node.attrs.fieldKey}: `;
         if (node.attrs.docid) {
             DocServer.GetRefField(node.attrs.docid).then(async dashDoc => dashDoc instanceof Doc && runInAction(() => setDashDoc(dashDoc)));
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 3c2cbb5b0..6ebd3194d 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -80,7 +80,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
         if (de.complete.docDragData) {
             (this.props.parent.Document.dropConverter instanceof ScriptField) &&
                 this.props.parent.Document.dropConverter.script.run({ dragData: de.complete.docDragData });
-            const key = StrCast(this.props.parent.props.Document.sectionFilter);
+            const key = StrCast(this.props.parent.props.Document._pivotField);
             const castedValue = this.getValue(this._heading);
             de.complete.docDragData.droppedDocuments.forEach(d => d[key] = castedValue);
             this.props.parent.onInternalDrop(e, de);
@@ -99,7 +99,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     @action
     headingChanged = (value: string, shiftDown?: boolean) => {
         this._createAliasSelected = false;
-        const key = StrCast(this.props.parent.props.Document.sectionFilter);
+        const key = StrCast(this.props.parent.props.Document._pivotField);
         const castedValue = this.getValue(value);
         if (castedValue) {
             if (this.props.parent.sectionHeaders) {
@@ -138,7 +138,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     @action
     addDocument = (value: string, shiftDown?: boolean) => {
         this._createAliasSelected = false;
-        const key = StrCast(this.props.parent.props.Document.sectionFilter);
+        const key = StrCast(this.props.parent.props.Document._pivotField);
         const newDoc = Docs.Create.TextDocument("", { _height: 18, _width: 200, title: value });
         newDoc[key] = this.getValue(this.props.heading);
         return this.props.parent.props.addDocument(newDoc);
@@ -146,7 +146,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
 
     deleteRow = undoBatch(action(() => {
         this._createAliasSelected = false;
-        const key = StrCast(this.props.parent.props.Document.sectionFilter);
+        const key = StrCast(this.props.parent.props.Document._pivotField);
         this.props.docList.forEach(d => d[key] = undefined);
         if (this.props.parent.sectionHeaders && this.props.headingObject) {
             const index = this.props.parent.sectionHeaders.indexOf(this.props.headingObject);
@@ -168,7 +168,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
         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) {
             const alias = Doc.MakeAlias(this.props.parent.props.Document);
-            const key = StrCast(this.props.parent.props.Document.sectionFilter);
+            const key = StrCast(this.props.parent.props.Document._pivotField);
             let value = this.getValue(this._heading);
             value = typeof value === "string" ? `"${value}"` : value;
             const script = `return doc.${key} === ${value}`;
@@ -296,7 +296,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
 
     @computed get headingView() {
         const heading = this._heading;
-        const key = StrCast(this.props.parent.props.Document.sectionFilter);
+        const key = StrCast(this.props.parent.props.Document._pivotField);
         const evContents = heading ? heading : this.props.type && this.props.type === "number" ? "0" : `NO ${key.toUpperCase()} VALUE`;
         const headerEditableViewProps = {
             GetValue: () => evContents,
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index d1f45af90..f84b0af20 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -31,21 +31,21 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     _masonryGridRef: HTMLDivElement | null = null;
     _draggerRef = React.createRef<HTMLDivElement>();
     _heightDisposer?: IReactionDisposer;
-    _sectionFilterDisposer?: IReactionDisposer;
+    _pivotFieldDisposer?: IReactionDisposer;
     _docXfs: any[] = [];
     _columnStart: number = 0;
     @observable _heightMap = new Map<string, number>();
     @observable _cursor: CursorProperty = "grab";
     @observable _scroll = 0; // used to force the document decoration to update when scrolling
     @computed get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); }
-    @computed get sectionFilter() { return StrCast(this.props.Document.sectionFilter); }
+    @computed get pivotField() { return StrCast(this.props.Document._pivotField); }
     @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc).map(pair => pair.layout); }
     @computed get xMargin() { return NumCast(this.props.Document._xMargin, 2 * Math.min(this.gridGap, .05 * this.props.PanelWidth())); }
     @computed get yMargin() { return Math.max(this.props.Document._showTitle && !this.props.Document._showTitleHover ? 30 : 0, NumCast(this.props.Document._yMargin, 0)); } // 2 * this.gridGap)); }
     @computed get gridGap() { return NumCast(this.props.Document._gridGap, 10); }
     @computed get isStackingView() { return BoolCast(this.props.Document.singleColumn, true); }
     @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; }
-    @computed get showAddAGroup() { return (this.sectionFilter && (this.props.Document._chromeStatus !== 'view-mode' && this.props.Document._chromeStatus !== 'disabled')); }
+    @computed get showAddAGroup() { return (this.pivotField && (this.props.Document._chromeStatus !== 'view-mode' && this.props.Document._chromeStatus !== 'disabled')); }
     @computed get columnWidth() {
         return Math.min(this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin,
             this.isStackingView ? Number.MAX_VALUE : NumCast(this.props.Document.columnWidth, 250));
@@ -73,7 +73,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
 
     get Sections() {
-        if (!this.sectionFilter || this.sectionHeaders instanceof Promise) return new Map<SchemaHeaderField, Doc[]>();
+        if (!this.pivotField || this.sectionHeaders instanceof Promise) return new Map<SchemaHeaderField, Doc[]>();
 
         if (this.sectionHeaders === undefined) {
             setTimeout(() => this.props.Document.sectionHeaders = new List<SchemaHeaderField>(), 0);
@@ -83,18 +83,18 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         const fields = new Map<SchemaHeaderField, Doc[]>(sectionHeaders.map(sh => [sh, []] as [SchemaHeaderField, []]));
         let changed = false;
         this.filteredChildren.map(d => {
-            const sectionValue = (d[this.sectionFilter] ? d[this.sectionFilter] : `NO ${this.sectionFilter.toUpperCase()} VALUE`) as object;
+            const sectionValue = (d[this.pivotField] ? d[this.pivotField] : `NO ${this.pivotField.toUpperCase()} VALUE`) as object;
             // the next five lines ensures that floating point rounding errors don't create more than one section -syip
             const parsed = parseInt(sectionValue.toString());
             const castedSectionValue = !isNaN(parsed) ? parsed : sectionValue;
 
             // look for if header exists already
-            const existingHeader = sectionHeaders.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO ${this.sectionFilter.toUpperCase()} VALUE`));
+            const existingHeader = sectionHeaders.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO ${this.pivotField.toUpperCase()} VALUE`));
             if (existingHeader) {
                 fields.get(existingHeader)!.push(d);
             }
             else {
-                const newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `NO ${this.sectionFilter.toUpperCase()} VALUE`);
+                const newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `NO ${this.pivotField.toUpperCase()} VALUE`);
                 fields.set(newSchemaHeader, [d]);
                 sectionHeaders.push(newSchemaHeader);
                 changed = true;
@@ -134,15 +134,15 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         );
 
         // reset section headers when a new filter is inputted
-        this._sectionFilterDisposer = reaction(
-            () => this.sectionFilter,
+        this._pivotFieldDisposer = reaction(
+            () => this.pivotField,
             () => this.props.Document.sectionHeaders = new List()
         );
     }
     componentWillUnmount() {
         super.componentWillUnmount();
-        this._heightDisposer && this._heightDisposer();
-        this._sectionFilterDisposer && this._sectionFilterDisposer();
+        this._heightDisposer?.();
+        this._pivotFieldDisposer?.();
     }
 
     @action
@@ -278,7 +278,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
     headings = () => Array.from(this.Sections.keys());
     sectionStacking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
-        const key = this.sectionFilter;
+        const key = this.pivotField;
         let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined;
         const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]);
         if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) {
@@ -313,7 +313,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
 
     sectionMasonry = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
-        const key = this.sectionFilter;
+        const key = this.pivotField;
         let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined;
         const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]);
         if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) {
@@ -341,7 +341,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         if (value && this.sectionHeaders) {
             const schemaHdrField = new SchemaHeaderField(value);
             this.sectionHeaders.push(schemaHdrField);
-            Doc.addEnumerationToTextField(undefined, this.sectionFilter, [Docs.Create.TextDocument(value, { title: value, _backgroundColor: schemaHdrField.color })]);
+            Doc.addEnumerationToTextField(undefined, this.pivotField, [Docs.Create.TextDocument(value, { title: value, _backgroundColor: schemaHdrField.color })]);
             return true;
         }
         return false;
@@ -370,7 +370,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @computed get renderedSections() {
         TraceMobx();
         let sections = [[undefined, this.filteredChildren] as [SchemaHeaderField | undefined, Doc[]]];
-        if (this.sectionFilter) {
+        if (this.pivotField) {
             const entries = Array.from(this.Sections.entries());
             sections = entries.sort(this.sortFunc);
         }
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 516e583d4..646b433bf 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -23,7 +23,6 @@ import { CollectionStackingView } from "./CollectionStackingView";
 import { setupMoveUpEvents, emptyFunction } from "../../../Utils";
 import "./CollectionStackingView.scss";
 import { listSpec } from "../../../new_fields/Schema";
-import { Schema } from "prosemirror-model";
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -62,7 +61,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
     @undoBatch
     columnDrop = action((e: Event, de: DragManager.DropEvent) => {
         if (de.complete.docDragData) {
-            const key = StrCast(this.props.parent.props.Document.sectionFilter);
+            const key = StrCast(this.props.parent.props.Document._pivotField);
             const castedValue = this.getValue(this._heading);
             de.complete.docDragData.droppedDocuments.forEach(d => Doc.SetInPlace(d, key, castedValue, false));
             this.props.parent.onInternalDrop(e, de);
@@ -85,7 +84,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
 
     @action
     headingChanged = (value: string, shiftDown?: boolean) => {
-        const key = StrCast(this.props.parent.props.Document.sectionFilter);
+        const key = StrCast(this.props.parent.props.Document._pivotField);
         const castedValue = this.getValue(value);
         if (castedValue) {
             if (this.props.parent.sectionHeaders) {
@@ -126,7 +125,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
     @action
     addDocument = (value: string, shiftDown?: boolean) => {
         if (!value) return false;
-        const key = StrCast(this.props.parent.props.Document.sectionFilter);
+        const key = StrCast(this.props.parent.props.Document._pivotField);
         const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, title: value, _autoHeight: true });
         newDoc[key] = this.getValue(this.props.heading);
         const maxHeading = this.props.docList.reduce((maxHeading, doc) => NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0);
@@ -137,7 +136,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
 
     @action
     deleteColumn = () => {
-        const key = StrCast(this.props.parent.props.Document.sectionFilter);
+        const key = StrCast(this.props.parent.props.Document._pivotField);
         this.props.docList.forEach(d => d[key] = undefined);
         if (this.props.parent.sectionHeaders && this.props.headingObject) {
             const index = this.props.parent.sectionHeaders.indexOf(this.props.headingObject);
@@ -161,8 +160,8 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
     startDrag = (e: PointerEvent, down: number[], delta: number[]) => {
         const alias = Doc.MakeAlias(this.props.parent.props.Document);
         alias._width = this.props.parent.props.PanelWidth() / (Cast(this.props.parent.props.Document.sectionHeaders, listSpec(SchemaHeaderField))?.length || 1);
-        alias.sectionFilter = undefined;
-        const key = StrCast(this.props.parent.props.Document.sectionFilter);
+        alias._pivotField = undefined;
+        const key = StrCast(this.props.parent.props.Document._pivotField);
         let value = this.getValue(this._heading);
         value = typeof value === "string" ? `"${value}"` : value;
         alias.viewSpecScript = ScriptField.MakeFunction(`doc.${key} === ${value}`, { doc: Doc.name });
@@ -277,7 +276,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
     render() {
         TraceMobx();
         const cols = this.props.cols();
-        const key = StrCast(this.props.parent.props.Document.sectionFilter);
+        const key = StrCast(this.props.parent.props.Document._pivotField);
         let templatecols = "";
         const headings = this.props.headings();
         const heading = this._heading;
diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss
index 8602b2369..19a14976c 100644
--- a/src/client/views/collections/CollectionViewChromes.scss
+++ b/src/client/views/collections/CollectionViewChromes.scss
@@ -169,21 +169,21 @@
         }
 
 
-        .collectionStackingViewChrome-sectionFilter-cont,
-        .collectionTreeViewChrome-sectionFilter-cont {
+        .collectionStackingViewChrome-pivotField-cont,
+        .collectionTreeViewChrome-pivotField-cont {
             justify-self: right;
             display: flex;
             font-size: 75%;
             letter-spacing: 2px;
 
-            .collectionStackingViewChrome-sectionFilter-label,
-            .collectionTreeViewChrome-sectionFilter-label {
+            .collectionStackingViewChrome-pivotField-label,
+            .collectionTreeViewChrome-pivotField-label {
                 vertical-align: center;
                 padding: 10px;
             }
 
-            .collectionStackingViewChrome-sectionFilter,
-            .collectionTreeViewChrome-sectionFilter {
+            .collectionStackingViewChrome-pivotField,
+            .collectionTreeViewChrome-pivotField {
                 color: white;
                 width: 100px;
                 text-align: center;
@@ -210,8 +210,8 @@
             }
         }
 
-        .collectionStackingViewChrome-sectionFilter:hover,
-        .collectionTreeViewChrome-sectionFilter:hover {
+        .collectionStackingViewChrome-pivotField:hover,
+        .collectionTreeViewChrome-pivotField:hover {
             cursor: text;
         }
     }
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 4f504ab1c..57a73000d 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -166,7 +166,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
             this._viewSpecsOpen = true;
 
             //@ts-ignore
-            if (!e.target ?.classList[0] ?.startsWith("qs")) {
+            if (!e.target?.classList[0]?.startsWith("qs")) {
                 this.closeDatePicker();
             }
 
@@ -291,7 +291,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
     @action
     protected drop(e: Event, de: DragManager.DropEvent): boolean {
         if (de.complete.docDragData && de.complete.docDragData.draggedDocuments.length) {
-            this._buttonizableCommands.filter(c => c.title === this._currentKey).map(c => c.immediate(de.complete.docDragData ?.draggedDocuments || []));
+            this._buttonizableCommands.filter(c => c.title === this._currentKey).map(c => c.immediate(de.complete.docDragData?.draggedDocuments || []));
             e.stopPropagation();
         }
         return true;
@@ -472,7 +472,7 @@ export class CollectionStackingViewChrome extends React.Component<CollectionView
     @observable private suggestions: string[] = [];
 
     @computed private get descending() { return BoolCast(this.props.CollectionView.props.Document.stackingHeadersSortDescending); }
-    @computed get sectionFilter() { return StrCast(this.props.CollectionView.props.Document.sectionFilter); }
+    @computed get pivotField() { return StrCast(this.props.CollectionView.props.Document._pivotField); }
 
     getKeySuggestions = async (value: string): Promise<string[]> => {
         value = value.toLowerCase();
@@ -510,26 +510,26 @@ export class CollectionStackingViewChrome extends React.Component<CollectionView
     }
 
     setValue = (value: string) => {
-        this.props.CollectionView.props.Document.sectionFilter = value;
+        this.props.CollectionView.props.Document._pivotField = value;
         return true;
     }
 
     @action toggleSort = () => { this.props.CollectionView.props.Document.stackingHeadersSortDescending = !this.props.CollectionView.props.Document.stackingHeadersSortDescending; };
-    @action resetValue = () => { this._currentKey = this.sectionFilter; };
+    @action resetValue = () => { this._currentKey = this.pivotField; };
 
     render() {
         return (
             <div className="collectionStackingViewChrome-cont">
-                <div className="collectionStackingViewChrome-sectionFilter-cont">
-                    <div className="collectionStackingViewChrome-sectionFilter-label">
+                <div className="collectionStackingViewChrome-pivotField-cont">
+                    <div className="collectionStackingViewChrome-pivotField-label">
                         GROUP ITEMS BY:
                     </div>
                     <div className="collectionStackingViewChrome-sortIcon" onClick={this.toggleSort} style={{ transform: `rotate(${this.descending ? "180" : "0"}deg)` }}>
                         <FontAwesomeIcon icon="caret-up" size="2x" color="white" />
                     </div>
-                    <div className="collectionStackingViewChrome-sectionFilter">
+                    <div className="collectionStackingViewChrome-pivotField">
                         <EditableView
-                            GetValue={() => this.sectionFilter}
+                            GetValue={() => this.pivotField}
                             autosuggestProps={
                                 {
                                     resetValue: this.resetValue,
@@ -551,7 +551,7 @@ export class CollectionStackingViewChrome extends React.Component<CollectionView
                                 }}
                             oneLine
                             SetValue={this.setValue}
-                            contents={this.sectionFilter ? this.sectionFilter : "N/A"}
+                            contents={this.pivotField ? this.pivotField : "N/A"}
                         />
                     </div>
                 </div>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 055be7f86..ea86bff99 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,20 +1,22 @@
 import { library } from "@fortawesome/fontawesome-svg-core";
 import { faEye } from "@fortawesome/free-regular-svg-icons";
-import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload, faTextHeight } from "@fortawesome/free-solid-svg-icons";
-import { action, computed, observable, ObservableMap, reaction, runInAction, IReactionDisposer } from "mobx";
+import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons";
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { computedFn } from "mobx-utils";
-import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocCastAsync } from "../../../../new_fields/Doc";
+import { Doc, HeightSym, Opt, WidthSym } from "../../../../new_fields/Doc";
 import { documentSchema, positionSchema } from "../../../../new_fields/documentSchemas";
 import { Id } from "../../../../new_fields/FieldSymbols";
-import { InkTool, InkField, InkData } from "../../../../new_fields/InkField";
+import { InkData, InkField, InkTool } from "../../../../new_fields/InkField";
+import { List } from "../../../../new_fields/List";
+import { RichTextField } from "../../../../new_fields/RichTextField";
 import { createSchema, listSpec, makeInterface } from "../../../../new_fields/Schema";
 import { ScriptField } from "../../../../new_fields/ScriptField";
-import { Cast, NumCast, ScriptCast, BoolCast, StrCast, FieldValue } from "../../../../new_fields/Types";
+import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../new_fields/Types";
 import { TraceMobx } from "../../../../new_fields/util";
 import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
-import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils";
 import { aggregateBounds, intersectRect, returnOne, Utils } from "../../../../Utils";
+import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
 import { DocServer } from "../../../DocServer";
 import { Docs } from "../../../documents/Documents";
 import { DocumentManager } from "../../../util/DocumentManager";
@@ -29,10 +31,11 @@ import { ContextMenu } from "../../ContextMenu";
 import { ContextMenuProps } from "../../ContextMenuItem";
 import { InkingControl } from "../../InkingControl";
 import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
-import { DocumentContentsView } from "../../nodes/DocumentContentsView";
+import { DocumentViewProps } from "../../nodes/DocumentView";
 import { FormattedTextBox } from "../../nodes/FormattedTextBox";
 import { pageSchema } from "../../nodes/ImageBox";
 import PDFMenu from "../../pdf/PDFMenu";
+import { CollectionDockingView } from "../CollectionDockingView";
 import { CollectionSubView } from "../CollectionSubView";
 import { computePivotLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from "./CollectionFreeFormLayoutEngines";
 import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors";
@@ -40,13 +43,6 @@ import "./CollectionFreeFormView.scss";
 import MarqueeOptionsMenu from "./MarqueeOptionsMenu";
 import { MarqueeView } from "./MarqueeView";
 import React = require("react");
-import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
-import { RichTextField } from "../../../../new_fields/RichTextField";
-import { List } from "../../../../new_fields/List";
-import { DocumentViewProps } from "../../nodes/DocumentView";
-import { CollectionDockingView } from "../CollectionDockingView";
-import { MainView } from "../../MainView";
-import { TouchScrollableMenuItem } from "../../TouchScrollableMenu";
 
 library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload);
 
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 6216ab7e6..0f8d8fec8 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -254,7 +254,7 @@ export class CurrentUserUtils {
 
         // Finally, setup the list of buttons to display in the sidebar
         doc.sidebarButtons = Docs.Create.StackingDocument([doc.SearchBtn as Doc, doc.LibraryBtn as Doc, doc.ToolsBtn as Doc], {
-            _width: 500, _height: 80, boxShadow: "0 0", sectionFilter: "title", hideHeadings: true, ignoreClick: true,
+            _width: 500, _height: 80, boxShadow: "0 0", _pivotField: "title", hideHeadings: true, ignoreClick: true,
             _chromeStatus: "disabled", title: "library stack", backgroundColor: "dimGray",
         });
     }
-- 
cgit v1.2.3-70-g09d2


From a88608f33c15a79fecda08e3fddb5bc7690af127 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 3 Mar 2020 21:19:20 -0500
Subject: fixed enumerations a bit.

---
 src/client/documents/Documents.ts                  |  1 +
 src/client/util/RichTextSchema.tsx                 | 57 ++++++++++------------
 .../views/collections/CollectionStackingView.tsx   |  2 +-
 src/new_fields/Doc.ts                              | 35 ++++---------
 .../authentication/models/current_user_utils.ts    | 16 +++---
 5 files changed, 44 insertions(+), 67 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 6b25b3897..b06ff5465 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -108,6 +108,7 @@ export interface DocumentOptions {
     _backgroundColor?: string | ScriptField; // background color for each template layout doc ( overrides backgroundColor )
     color?: string; // foreground color data doc
     _color?: string;  // foreground color for each template layout doc (overrides color)
+    caption?: RichTextField;
     ignoreClick?: boolean;
     lockedPosition?: boolean; // lock the x,y coordinates of the document so that it can't be dragged
     lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 2c3714310..649908317 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -887,32 +887,10 @@ export class DashFieldView {
 
         this._enumerables.onpointerdown = async (e) => {
             e.stopPropagation();
-            const collview = await Doc.addEnumerationToTextField(self._textBoxDoc, node.attrs.fieldKey, [Docs.Create.TextDocument(self._fieldSpan.innerText, { title: self._fieldSpan.innerText })]);
+            const collview = await Doc.addFieldEnumerations(self._textBoxDoc, node.attrs.fieldKey, [{ title: self._fieldSpan.innerText }]);
             collview instanceof Doc && tbox.props.addDocTab(collview, "onRight");
         }
-
-        this._fieldSpan = document.createElement("div");
-        this._fieldSpan.id = Utils.GenerateGuid();
-        this._fieldSpan.contentEditable = "true";
-        this._fieldSpan.style.position = "relative";
-        this._fieldSpan.style.display = "inline-block";
-        this._fieldSpan.style.minWidth = "5px";
-        this._fieldSpan.style.backgroundColor = "rgba(155, 155, 155, 0.24)";
-        this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); };
-        this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); };
-        this._fieldSpan.onmousedown = function (e: any) {
-            e.stopPropagation();
-            self._enumerables.style.display = "inline-block";
-        };
-        this._fieldSpan.oncontextmenu = function (e: any) {
-            ContextMenu.Instance.addItem({
-                description: "Show Enumeration Templates", event: () => {
-                    e.stopPropagation();
-                    DocServer.GetRefField(node.attrs.fieldKey).then(collview => collview instanceof Doc && tbox.props.addDocTab(collview, "onRight"));
-                }, icon: "expand-arrows-alt"
-            });
-        };
-        this._fieldSpan.onblur = function (e: any) {
+        const updateText = (forceMatch: boolean) => {
             self._enumerables.style.display = "none";
             let newText = self._fieldSpan.innerText.startsWith(":=") ? ":=-computed-" : self._fieldSpan.innerText;
 
@@ -920,8 +898,12 @@ export class DashFieldView {
             // holds the different enumerated values for the field in the titles of its collected documents.
             // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down.
             DocServer.GetRefField(node.attrs.fieldKey).then(options => {
-                (options instanceof Doc) && DocListCast(options.data).forEach(opt => StrCast(opt.title).startsWith(newText) && (newText = StrCast(opt.title)));
-                self._fieldSpan.innerHTML = self._dashDoc![self._fieldKey] = newText;
+                let modText = "";
+                (options instanceof Doc) && DocListCast(options.data).forEach(opt => (forceMatch ? StrCast(opt.title).startsWith(newText) : StrCast(opt.title) === newText) && (modText = StrCast(opt.title)));
+                if (modText) {
+                    self._fieldSpan.innerHTML = self._dashDoc![self._fieldKey] = modText;
+                    Doc.addFieldEnumerations(self._textBoxDoc, node.attrs.fieldKey, []);
+                }
 
                 // if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key
                 if (newText.startsWith(":=") && self._dashDoc && e.data === null && !e.inputType.includes("delete")) {
@@ -930,10 +912,22 @@ export class DashFieldView {
             });
         }
 
+        this._fieldSpan = document.createElement("div");
+        this._fieldSpan.id = Utils.GenerateGuid();
+        this._fieldSpan.contentEditable = "true";
+        this._fieldSpan.style.position = "relative";
+        this._fieldSpan.style.display = "inline-block";
+        this._fieldSpan.style.minWidth = "5px";
+        this._fieldSpan.style.backgroundColor = "rgba(155, 155, 155, 0.24)";
+        this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); };
+        this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); };
+        this._fieldSpan.onmousedown = function (e: any) { e.stopPropagation(); self._enumerables.style.display = "inline-block"; };
+        this._fieldSpan.onblur = function (e: any) { updateText(false); }
+
         const setDashDoc = (doc: Doc) => {
             self._dashDoc = doc;
-            if (this._dashDoc && self._options?.length && !this._dashDoc[node.attrs.fieldKey]) {
-                this._dashDoc[node.attrs.fieldKey] = StrCast(self._options[0].title);
+            if (self._dashDoc && self._options?.length && !self._dashDoc[node.attrs.fieldKey]) {
+                self._dashDoc[node.attrs.fieldKey] = StrCast(self._options[0].title);
             }
         }
         this._fieldSpan.onkeydown = function (e: any) {
@@ -949,10 +943,8 @@ export class DashFieldView {
             }
             if (e.key === "Enter") {
                 e.preventDefault();
-                if (e.ctrlKey) {
-                    Doc.addEnumerationToTextField(self._textBoxDoc, node.attrs.fieldKey, [Docs.Create.TextDocument(self._fieldSpan.innerText, { title: self._fieldSpan.innerText })]);
-                }
-                self._fieldSpan.onblur?.(undefined as any);
+                e.ctrlKey && Doc.addFieldEnumerations(self._textBoxDoc, node.attrs.fieldKey, [{ title: self._fieldSpan.innerText }]);
+                updateText(true);
             }
         };
 
@@ -997,6 +989,7 @@ export class DashFieldView {
         this._fieldWrapper.appendChild(this._fieldSpan);
         this._fieldWrapper.appendChild(this._enumerables);
         (this as any).dom = this._fieldWrapper;
+        updateText(false);
     }
     destroy() {
         this._reactionDisposer?.();
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index f84b0af20..3f7f0a352 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -341,7 +341,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         if (value && this.sectionHeaders) {
             const schemaHdrField = new SchemaHeaderField(value);
             this.sectionHeaders.push(schemaHdrField);
-            Doc.addEnumerationToTextField(undefined, this.pivotField, [Docs.Create.TextDocument(value, { title: value, _backgroundColor: schemaHdrField.color })]);
+            Doc.addFieldEnumerations(undefined, this.pivotField, [{ title: value, _backgroundColor: schemaHdrField.color }]);
             return true;
         }
         return false;
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 6d94f050c..ce69d95b7 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -847,40 +847,23 @@ export namespace Doc {
         return id;
     }
 
-    // setup a document to use enumerated values for a specified field name:
-    //  doc: text document
-    //  layoutString: species which text field receives the document's main text (e.g., FormattedTextBox.LayoutString("Todo") )
-    //  enumeratedFieldKey : specifies which enumerated field of the document is displayed in the caption (e.g., taskStatus)
-    //  captionKey: specifies which field holds the caption template (e.g., caption) -- ideally this wouldn't be needed but would be derived from the layoutString's target field key
-    //
-    export function enumeratedTextTemplate(doc: Doc, layoutString: string, enumeratedFieldKey: string, enumeratedDocs: Doc[], captionKey: string = "caption") {
-        doc.caption = RichTextField.DashField(enumeratedFieldKey);
-        doc._showCaption = captionKey;
-        doc.layout = layoutString;
-
-        Doc.addEnumerationToTextField(doc, enumeratedFieldKey, enumeratedDocs);
-    }
-
-    export async function getEnumerationTextField(enumeratedFieldKey: string) {
-        return (await DocServer.GetRefField(enumeratedFieldKey)) as Doc;
-    }
-
-    export async function addEnumerationToTextField(doc: Opt<Doc>, enumeratedFieldKey: string, enumeratedDocs: Doc[]) {
+    export async function addFieldEnumerations(doc: Opt<Doc>, enumeratedFieldKey: string, enumerations: { title: string, _backgroundColor?: string, color?: string }[]) {
         let optionsCollection = await DocServer.GetRefField(enumeratedFieldKey);
         if (!(optionsCollection instanceof Doc)) {
             optionsCollection = Docs.Create.StackingDocument([], { title: `${enumeratedFieldKey} field set` }, enumeratedFieldKey);
             Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc);
         }
         const options = optionsCollection as Doc;
-        doc && (Doc.GetProto(doc).backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey})?._backgroundColor || "white"`, undefined, { options }));
-        doc && (Doc.GetProto(doc).color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey}).color || "black"`, undefined, { options }));
-        enumeratedDocs.map(enumeratedDoc => {
-            const found = DocListCast(options.data).find(d => d.title === enumeratedDoc.title);
+        const targetDoc = doc && Doc.GetProto(Cast(doc.expandedTemplate, Doc, null) || doc);
+        targetDoc && (targetDoc.backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this)["${enumeratedFieldKey}"])?._backgroundColor || "white"`, undefined, { options }));
+        targetDoc && (targetDoc.color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this)["${enumeratedFieldKey}"]).color || "black"`, undefined, { options }));
+        enumerations.map(enumeration => {
+            const found = DocListCast(options.data).find(d => d.title === enumeration.title);
             if (found) {
-                found._backgroundColor = enumeratedDoc._backgroundColor || found._backgroundColor;
-                found._color = enumeratedDoc._color || found._color;
+                found._backgroundColor = enumeration._backgroundColor || found._backgroundColor;
+                found._color = enumeration.color || found._color;
             } else {
-                Doc.AddDocToList(options, "data", enumeratedDoc);
+                Doc.AddDocToList(options, "data", Docs.Create.TextDocument(enumeration.title, enumeration));
             }
         });
         return optionsCollection;
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 0f8d8fec8..f672da085 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -37,20 +37,20 @@ export class CurrentUserUtils {
     @observable public static GuestMobile: Doc | undefined;
 
     static setupDefaultDocTemplates(doc: Doc, buttons?: string[]) {
-        const taskStatusValues = [
-            Docs.Create.TextDocument("todo", { title: "todo", _backgroundColor: "blue", color: "white" }),
-            Docs.Create.TextDocument("in progress", { title: "in progress", _backgroundColor: "yellow", color: "black" }),
-            Docs.Create.TextDocument("completed", { title: "completed", _backgroundColor: "green", color: "white" })
+        const taskStatusValues = [  { title: "todo", _backgroundColor: "blue", color: "white" },
+                                    { title: "in progress", _backgroundColor: "yellow", color: "black" },
+                                    { title: "completed", _backgroundColor: "green", color: "white" }
         ];
         const noteTemplates = [
             Docs.Create.TextDocument("", { title: "text", style: "Note", isTemplateDoc: true, backgroundColor: "yellow" }),
             Docs.Create.TextDocument("", { title: "text", style: "Idea", isTemplateDoc: true, backgroundColor: "pink" }),
             Docs.Create.TextDocument("", { title: "text", style: "Topic", isTemplateDoc: true, backgroundColor: "lightBlue" }),
             Docs.Create.TextDocument("", { title: "text", style: "Person", isTemplateDoc: true, backgroundColor: "lightGreen" }),
-            Docs.Create.TextDocument("", { title: "text", style: "Todo", isTemplateDoc: true, backgroundColor: "orange", _autoHeight: false, _height: 100, _showCaption: "caption" })
+            Docs.Create.TextDocument("", { title: "text", style: "Todo", isTemplateDoc: true, backgroundColor: "orange",_autoHeight: false, 
+                layout:FormattedTextBox.LayoutString("Todo"), _height: 100, _showCaption: "caption",caption: RichTextField.DashField("taskStatus") })
         ];
         doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" });
-        Doc.enumeratedTextTemplate(Doc.GetProto(noteTemplates[4]), FormattedTextBox.LayoutString("Todo"), "taskStatus", taskStatusValues);
+        Doc.addFieldEnumerations(Doc.GetProto(noteTemplates[4]), "taskStatus", taskStatusValues);
         doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt, true, StrCast(nt.style)) ? nt : nt), { title: "Note Types", _height: 75 }));
     }
 
@@ -268,9 +268,9 @@ export class CurrentUserUtils {
             ],
             { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false });
         slideTemplate.isTemplateDoc = makeTemplate(slideTemplate);
-        const descriptionTemplate = Docs.Create.TextDocument("", { title: "descriptionView", _height: 100, _showTitle: "title" });
+        const descriptionTemplate = Docs.Create.TextDocument("", { title: "text", _height: 100, _showTitle: "title" });
         Doc.GetProto(descriptionTemplate).layout = FormattedTextBox.LayoutString("description");
-        descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate);
+        descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView");
 
         const iconDoc = Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onClick: ScriptField.MakeScript("setNativeView(this)") });
         Doc.GetProto(iconDoc).data = new RichTextField('{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"title","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}', "");
-- 
cgit v1.2.3-70-g09d2


From d466e368ad164347f82a160e7088540a78c230f6 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 10 Mar 2020 11:07:59 -0400
Subject: made stacking view hide edit/view button unless selected.  get rid of
 columns with no documens when hideHeadings is set.

---
 src/client/views/collections/CollectionStackingView.tsx | 12 ++++++++++--
 src/server/authentication/models/current_user_utils.ts  |  4 ++--
 2 files changed, 12 insertions(+), 4 deletions(-)

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 3f7f0a352..a936582c3 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -100,6 +100,14 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                 changed = true;
             }
         });
+        // remove all empty columns if hideHeadings is set
+        if (this.props.Document.hideHeadings) {
+            Array.from(fields.keys()).filter(key => !fields.get(key)!.length).map(header => {
+                fields.delete(header);
+                sectionHeaders.splice(sectionHeaders.indexOf(header), 1);
+                changed = true;
+            })
+        }
         changed && setTimeout(action(() => { if (this.sectionHeaders) { this.sectionHeaders.length = 0; this.sectionHeaders.push(...sectionHeaders); } }), 0);
         return fields;
     }
@@ -276,7 +284,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             }
         });
     }
-    headings = () => Array.from(this.Sections.keys());
+    headings = () => Array.from(this.Sections);
     sectionStacking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
         const key = this.pivotField;
         let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined;
@@ -407,7 +415,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                             style={{ width: !this.isStackingView ? "100%" : this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}>
                             <EditableView {...editableViewProps} />
                         </div>}
-                    {this.props.Document._chromeStatus !== 'disabled' ? <Switch
+                    {this.props.Document._chromeStatus !== 'disabled' && this.props.isSelected() ? <Switch
                         onChange={this.onToggle}
                         onClick={this.onToggle}
                         defaultChecked={this.props.Document._chromeStatus !== 'view-mode'}
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 15f626af4..0fbc596af 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -256,8 +256,8 @@ export class CurrentUserUtils {
 
         // Finally, setup the list of buttons to display in the sidebar
         doc.sidebarButtons = Docs.Create.StackingDocument([doc.SearchBtn as Doc, doc.LibraryBtn as Doc, doc.ToolsBtn as Doc], {
-            _width: 500, _height: 80, boxShadow: "0 0", _pivotField: "title", hideHeadings: true, ignoreClick: true,
-            _chromeStatus: "disabled", title: "library stack", backgroundColor: "dimGray",
+            _width: 500, _height: 80, boxShadow: "0 0", _pivotField: "title", hideHeadings: true, ignoreClick: true, _chromeStatus: "view-mode",
+            title: "sidebar btn row stack", backgroundColor: "dimGray",
         });
     }
 
-- 
cgit v1.2.3-70-g09d2


From 61e12f2e08ed0c0e47b82456b75c441b7278cdd6 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 19 Mar 2020 15:53:07 -0400
Subject: fixed buttons on screenshotbox.  added 'place' option to dragDrop to
 drop the original document without moving it.   switched to passing
 childDropAction as a prop

---
 src/client/util/DragManager.ts                     |  2 +-
 .../views/collections/CollectionStackingView.tsx   |  3 +-
 .../views/collections/CollectionTreeView.tsx       |  5 +--
 src/client/views/collections/CollectionView.tsx    | 25 ++++++-------
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  3 +-
 .../views/nodes/ContentFittingDocumentView.tsx     |  3 ++
 src/client/views/nodes/DocumentView.tsx            |  6 ++--
 src/client/views/nodes/FieldView.tsx               |  1 +
 src/client/views/nodes/ScreenshotBox.scss          | 41 +++++++++++++---------
 src/client/views/nodes/ScreenshotBox.tsx           |  7 ++--
 .../authentication/models/current_user_utils.ts    |  2 +-
 11 files changed, 58 insertions(+), 40 deletions(-)

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

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index f4461d2f7..63a11c85a 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -18,7 +18,7 @@ import { AudioBox } from "../views/nodes/AudioBox";
 import { DateField } from "../../new_fields/DateField";
 import { DocumentView } from "../views/nodes/DocumentView";
 
-export type dropActionType = "alias" | "copy" | undefined;
+export type dropActionType = "place" | "alias" | "copy" | undefined;
 export function SetupDrag(
     _reference: React.RefObject<HTMLElement>,
     docFunc: () => Doc | Promise<Doc> | undefined,
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index a936582c3..719778eb1 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -12,7 +12,7 @@ import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types";
 import { TraceMobx } from "../../../new_fields/util";
 import { Utils, setupMoveUpEvents, emptyFunction } from "../../../Utils";
-import { DragManager } from "../../util/DragManager";
+import { DragManager, dropActionType } from "../../util/DragManager";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
 import { ContextMenu } from "../ContextMenu";
@@ -176,6 +176,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             LibraryPath={this.props.LibraryPath}
             renderDepth={this.props.renderDepth + 1}
             fitToBox={this.props.fitToBox}
+            dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             onClick={layoutDoc.isTemplateDoc ? this.onClickHandler : this.onChildClickHandler}
             PanelWidth={width}
             PanelHeight={height}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 4757e5a53..f8f8a0943 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -130,7 +130,7 @@ class TreeView extends React.Component<TreeViewProps> {
     }
 
     @undoBatch delete = () => this.props.deleteDoc(this.props.document);
-    @undoBatch openRight = () => this.props.addDocTab(this.props.containingCollection.childDropAction === "alias" ? Doc.MakeAlias(this.props.document) : this.props.document, "onRight", this.props.libraryPath);
+    @undoBatch openRight = () => this.props.addDocTab(this.props.dropAction === "alias" ? Doc.MakeAlias(this.props.document) : this.props.document, "onRight", this.props.libraryPath);
     @undoBatch indent = () => this.props.addDocument(this.props.document) && this.delete();
     @undoBatch move = (doc: Doc, target: Doc | undefined, addDoc: (doc: Doc) => boolean) => {
         return this.props.document !== target && this.props.deleteDoc(doc) && addDoc(doc);
@@ -455,6 +455,7 @@ class TreeView extends React.Component<TreeViewProps> {
                         addDocTab={this.props.addDocTab}
                         pinToPres={emptyFunction}
                         onClick={editTitle}
+                        dropAction={this.props.dropAction}
                         moveDocument={this.props.moveDocument}
                         removeDocument={undefined}
                         ScreenToLocalTransform={this.getTransform}
@@ -761,7 +762,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
     }
 
     render() {
-        const dropAction = StrCast(this.props.Document.dropAction) as dropActionType;
+        const dropAction = StrCast(this.props.Document.childDropAction) as dropActionType;
         const addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before);
         const moveDoc = (d: Doc, target: Doc | undefined, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc);
         const childDocs = this.props.overrideDocuments ? this.props.overrideDocuments : this.childDocs;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index c74b9ad6d..edac59efe 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,18 +1,17 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faEye } from '@fortawesome/free-regular-svg-icons';
 import { faColumns, faCopy, faEllipsisV, faFingerprint, faImage, faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree } from '@fortawesome/free-solid-svg-icons';
-import { action, IReactionDisposer, observable, reaction, runInAction, computed } from 'mobx';
+import { action, observable } from 'mobx';
 import { observer } from "mobx-react";
 import * as React from 'react';
 import Lightbox from 'react-image-lightbox-with-rotate';
 import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app
 import { DateField } from '../../../new_fields/DateField';
-import { Doc, DocListCast, DataSym } from '../../../new_fields/Doc';
-import { Id } from '../../../new_fields/FieldSymbols';
-import { BoolCast, Cast, StrCast, NumCast } from '../../../new_fields/Types';
+import { DataSym, Doc, DocListCast } from '../../../new_fields/Doc';
+import { List } from '../../../new_fields/List';
+import { BoolCast, Cast, NumCast, StrCast } from '../../../new_fields/Types';
 import { ImageField } from '../../../new_fields/URLField';
 import { TraceMobx } from '../../../new_fields/util';
-import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
 import { Utils } from '../../../Utils';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { DocumentManager } from '../../util/DocumentManager';
@@ -22,22 +21,23 @@ import { ContextMenu } from "../ContextMenu";
 import { FieldView, FieldViewProps } from '../nodes/FieldView';
 import { ScriptBox } from '../ScriptBox';
 import { Touchable } from '../Touchable';
+import { CollectionCarouselView } from './CollectionCarouselView';
 import { CollectionDockingView } from "./CollectionDockingView";
 import { AddCustomFreeFormLayout } from './collectionFreeForm/CollectionFreeFormLayoutEngines';
 import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
-import { CollectionCarouselView } from './CollectionCarouselView';
 import { CollectionLinearView } from './CollectionLinearView';
 import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView';
+import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView';
 import { CollectionSchemaView } from "./CollectionSchemaView";
 import { CollectionStackingView } from './CollectionStackingView';
 import { CollectionStaffView } from './CollectionStaffView';
+import { SubCollectionViewProps } from './CollectionSubView';
+import { CollectionTimeView } from './CollectionTimeView';
 import { CollectionTreeView } from "./CollectionTreeView";
 import './CollectionView.scss';
 import { CollectionViewBaseChrome } from './CollectionViewChromes';
-import { CollectionTimeView } from './CollectionTimeView';
-import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView';
-import { List } from '../../../new_fields/List';
-import { SubCollectionViewProps } from './CollectionSubView';
+import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
+import { Id } from '../../../new_fields/FieldSymbols';
 export const COLLECTION_BORDER_WIDTH = 2;
 const path = require('path');
 library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faEllipsisV, faImage, faEye as any, faCopy);
@@ -75,7 +75,7 @@ export namespace CollectionViewType {
     ]);
 
     export const valueOf = (value: string) => stringMapping.get(value.toLowerCase());
-    export const stringFor = (value: number) => Array.from(stringMapping.entries()).find(entry => entry[1] === value)[0];
+    export const stringFor = (value: number) => Array.from(stringMapping.entries()).find(entry => entry[1] === value)?.[0];
 }
 
 export interface CollectionRenderProps {
@@ -116,7 +116,8 @@ export class CollectionView extends Touchable<FieldViewProps> {
     @action.bound
     addDocument(doc: Doc): boolean {
         const targetDataDoc = this.props.Document[DataSym];
-        targetDataDoc[this.props.fieldKey] = new List<Doc>([...DocListCast(targetDataDoc[this.props.fieldKey]), doc]);  // DocAddToList may write to targetdataDoc's parent ... we don't want this. should really change GetProto to GetDataDoc and test for resolvedDataDoc there
+        const docList = DocListCast(targetDataDoc[this.props.fieldKey]);
+        !docList.includes(doc) && (targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, doc]));  // DocAddToList may write to targetdataDoc's parent ... we don't want this. should really change GetProto to GetDataDoc and test for resolvedDataDoc there
         // Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc);
         targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
         Doc.GetProto(doc).lastOpened = new DateField;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index fd679b7b2..da44d0d59 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -20,7 +20,7 @@ import { CognitiveServices } from "../../../cognitive_services/CognitiveServices
 import { DocServer } from "../../../DocServer";
 import { Docs } from "../../../documents/Documents";
 import { DocumentManager } from "../../../util/DocumentManager";
-import { DragManager } from "../../../util/DragManager";
+import { DragManager, dropActionType } from "../../../util/DragManager";
 import { HistoryUtil } from "../../../util/History";
 import { InteractionUtils } from "../../../util/InteractionUtils";
 import { SelectionManager } from "../../../util/SelectionManager";
@@ -832,6 +832,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             Document: childLayout,
             LibraryPath: this.libraryPath,
             layoutKey: undefined,
+            dropAction: StrCast(this.props.Document.childDropAction) as dropActionType,
             //onClick: undefined, // this.props.onClick,  // bcz: check this out -- I don't think we want to inherit click handlers, or we at least need a way to ignore them
             onClick: this.onChildClickHandler,
             ScreenToLocalTransform: childLayout.z ? this.getTransformOverlay : this.getTransform,
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 36233a7e6..8632f9c9a 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -12,6 +12,7 @@ import { CollectionView } from "../collections/CollectionView";
 import '../DocumentDecorations.scss';
 import { DocumentView } from "../nodes/DocumentView";
 import "./ContentFittingDocumentView.scss";
+import { dropActionType } from "../../util/DragManager";
 
 interface ContentFittingDocumentViewProps {
     Document?: Doc;
@@ -21,6 +22,7 @@ interface ContentFittingDocumentViewProps {
     childDocs?: Doc[];
     renderDepth: number;
     fitToBox?: boolean;
+    dropAction?: dropActionType;
     PanelWidth: () => number;
     PanelHeight: () => number;
     focus?: (doc: Doc) => void;
@@ -86,6 +88,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         LayoutDoc={this.props.LayoutDoc}
                         LibraryPath={this.props.LibraryPath}
                         fitToBox={this.props.fitToBox}
+                        dropAction={this.props.dropAction}
                         onClick={this.props.onClick}
                         backgroundColor={this.props.backgroundColor}
                         addDocument={this.props.addDocument}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c558a1da7..7480f0db8 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -14,7 +14,6 @@ import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
 import { AudioField, ImageField, PdfField, VideoField } from '../../../new_fields/URLField';
 import { TraceMobx } from '../../../new_fields/util';
 import { GestureUtils } from '../../../pen-gestures/GestureUtils';
-import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
 import { emptyFunction, returnOne, returnTransparent, returnTrue, Utils, OmitKeys } from "../../../Utils";
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { DocServer } from "../../DocServer";
@@ -65,6 +64,7 @@ export interface DocumentViewProps {
     onClick?: ScriptField;
     onPointerDown?: ScriptField;
     onPointerUp?: ScriptField;
+    dropAction?: dropActionType;
     dragDivName?: string;
     addDocument?: (doc: Doc) => boolean;
     removeDocument?: (doc: Doc) => boolean;
@@ -275,7 +275,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     onClick = (e: React.MouseEvent | React.PointerEvent) => {
-        if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick && CurrentUserUtils.MainDocId !== this.props.Document[Id] &&
+        if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick && //CurrentUserUtils.MainDocId !== this.props.Document[Id] &&
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
             e.stopPropagation();
             let preventDefault = true;
@@ -474,7 +474,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) {
                     document.removeEventListener("pointermove", this.onPointerMove);
                     document.removeEventListener("pointerup", this.onPointerUp);
-                    this.startDragging(this._downX, this._downY, this.props.ContainingCollectionDoc?.childDropAction ? this.props.ContainingCollectionDoc?.childDropAction : this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined);
+                    this.startDragging(this._downX, this._downY, this.props.dropAction ? this.props.dropAction : this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined);
                 }
             }
             e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document'  however it does mark the event as cancelBubble=true which we test for in the move event handlers
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index d030d1f4d..6619330a1 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -25,6 +25,7 @@ export interface FieldViewProps {
     DataDoc?: Doc;
     LibraryPath: Doc[];
     onClick?: ScriptField;
+    dropAction: dropAction;
     isSelected: (outsideReaction?: boolean) => boolean;
     select: (isCtrlPressed: boolean) => void;
     renderDepth: number;
diff --git a/src/client/views/nodes/ScreenshotBox.scss b/src/client/views/nodes/ScreenshotBox.scss
index 4aaccb472..6cc184948 100644
--- a/src/client/views/nodes/ScreenshotBox.scss
+++ b/src/client/views/nodes/ScreenshotBox.scss
@@ -25,22 +25,31 @@
     pointer-events: all;
 }
 
-.screenshotBox-snapshot{
-    color : white;
-    top :25px;
-    right : 25px;
+.screenshotBox-uiButtons {
+    background:dimgray;
+    border: orange solid 1px;
     position: absolute;
-    background-color:rgba(50, 50, 50, 0.2);
-    transform-origin: left top;
-    pointer-events:all;
-}
+    right: 25;
+    top: 0;
+    width:50;
+    height: 25;
+    .screenshotBox-snapshot{
+        color : white;
+        top :0px;
+        right : 5px;
+        position: absolute;
+        background-color:rgba(50, 50, 50, 0.2);
+        transform-origin: left top;
+        pointer-events:all;
+    }
 
-.screenshotBox-recorder{
-    color : white;
-    top :25px;
-    right : 50px;
-    position: absolute;
-    background-color:rgba(50, 50, 50, 0.2);
-    transform-origin: left top;
-    pointer-events:all;
+    .screenshotBox-recorder{
+        color : white;
+        top :0px;
+        left: 5px;
+        position: absolute;
+        background-color:rgba(50, 50, 50, 0.2);
+        transform-origin: left top;
+        pointer-events:all;
+    }
 }
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index cfa6fa8a3..548066f1c 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -145,13 +145,14 @@ export class ScreenshotBox extends DocAnnotatableComponent<FieldViewProps, Scree
     })
 
     private get uIButtons() {
-        return ([
+        return (<div className="screenshotBox-uiButtons">
             <div className="screenshotBox-recorder" key="snap" onPointerDown={this.toggleRecording} >
                 <FontAwesomeIcon icon="file" size="lg" />
             </div>,
             <div className="screenshotBox-snapshot" key="snap" onPointerDown={this.onSnapshot} >
                 <FontAwesomeIcon icon="camera" size="lg" />
-            </div>]);
+            </div>
+        </div>);
     }
 
     onSnapshot = (e: React.PointerEvent) => {
@@ -187,7 +188,7 @@ export class ScreenshotBox extends DocAnnotatableComponent<FieldViewProps, Scree
                     {this.contentFunc}
                 </CollectionFreeFormView>
             </div>
-            {this.uIButtons}
+            {this.active() ? this.uIButtons : (null)}
         </div >);
     }
 }
\ No newline at end of file
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index ea7b91b23..31588bf82 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -222,7 +222,7 @@ export class CurrentUserUtils {
             _width: 50, _height: 25, title: "Library", fontSize: 10, dontSelect: true,
             letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
             sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, Docs.Prototypes.MainLinkDocument(), doc, doc.recentlyClosed as Doc], {
-                title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, dropAction: "alias", lockedPosition: true, boxShadow: "0 0", dontRegisterChildren: true
+                title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "place", lockedPosition: true, boxShadow: "0 0", dontRegisterChildren: true
             }),
             targetContainer: sidebarContainer,
             onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;")
-- 
cgit v1.2.3-70-g09d2


From c0335eab060206d49020239788c43bb0626a467c Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 29 Mar 2020 19:11:16 -0400
Subject: fixed collection chrome pointerEvents.  fixed dontSelect to allow
 right-clicking.  got rid of '@" template field special case

---
 src/client/views/DocumentDecorations.tsx                | 2 +-
 src/client/views/collections/CollectionStackingView.tsx | 2 +-
 src/client/views/collections/CollectionViewChromes.tsx  | 5 +++--
 src/new_fields/util.ts                                  | 4 ----
 4 files changed, 5 insertions(+), 8 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index ff72592d8..3e07fd109 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -69,7 +69,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     get Bounds(): { x: number, y: number, b: number, r: number } {
         return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => {
             if (documentView.props.renderDepth === 0 ||
-                documentView.props.Document.dontSelect ||
+                //documentView.props.Document.dontSelect ||
                 Doc.AreProtosEqual(documentView.props.Document, CurrentUserUtils.UserDocument)) {
                 return bounds;
             }
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 719778eb1..9d5500e1a 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -170,7 +170,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         const height = () => this.getDocHeight(doc);
         return <ContentFittingDocumentView
             Document={doc}
-            DataDocument={doc[DataSym] !== doc && doc[DataSym]}
+            DataDocument={dataDoc || (doc[DataSym] !== doc && doc[DataSym])}
             backgroundColor={this.props.backgroundColor}
             LayoutDoc={this.props.childLayoutTemplate}
             LibraryPath={this.props.LibraryPath}
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index cfabad27c..53ee4c547 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -394,13 +394,14 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                 transformOrigin: "top left",
                 width: `${this.props.PanelWidth() / Math.min(1, this.props.CollectionView.props.ScreenToLocalTransform().Scale)}px`
             }}>
-                <div className="collectionViewChrome" style={{ border: "unset" }}>
+                <div className="collectionViewChrome" style={{ border: "unset", pointerEvents: collapsed ? "none" : undefined }}>
                     <div className="collectionViewBaseChrome">
                         <button className="collectionViewBaseChrome-collapse"
                             style={{
                                 top: collapsed ? 70 : 10,
                                 transform: `rotate(${collapsed ? 180 : 0}deg) scale(0.5) translate(${collapsed ? "-100%, -100%" : "0, 0"})`,
-                                opacity: (collapsed && !this.props.CollectionView.props.isSelected()) ? 0 : 0.9,
+                                opacity: 0.9,
+                                display: (collapsed && !this.props.CollectionView.props.isSelected()) ? "none" : undefined,
                                 left: (collapsed ? 0 : "unset"),
                             }}
                             title="Collapse collection chrome" onClick={this.toggleCollapse}>
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 080123965..3ab1b299b 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -128,10 +128,6 @@ export function getter(target: any, in_prop: string | symbol | number, receiver:
         }
         if (target.__LAYOUT__) return target.__LAYOUT__[prop];
     }
-    if (typeof prop === "string" && prop.startsWith("@")) {
-        const expanded = target.__fields["expandedTemplate"];
-        if (expanded) return expanded.cache[target.__fields[prop.substring(1)]];
-    }
     if (prop === "then") {//If we're being awaited
         return undefined;
     }
-- 
cgit v1.2.3-70-g09d2


From f5b883ce67117c06e5d498746038aacb7dfb126c Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 31 Mar 2020 19:27:29 -0400
Subject: fixed stacking view rendering of templates that treat regular docs
 like collections (eg slideView)

---
 src/client/views/collections/CollectionStackingView.tsx | 2 +-
 src/new_fields/Doc.ts                                   | 3 +--
 2 files changed, 2 insertions(+), 3 deletions(-)

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 9d5500e1a..086e0842e 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -63,7 +63,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap);
             const style = this.isStackingView ? { width: width(), marginTop: this.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` };
             return <div className={`collectionStackingView-${this.isStackingView ? "columnDoc" : "masonryDoc"}`} key={d[Id]} ref={dref} style={style} >
-                {this.getDisplayDoc(d, this.props.DataDoc, dxf, width)}
+                {this.getDisplayDoc(d, (!d.isTemplateDoc && !d.isTemplateForField && !d.PARAMS) ? undefined : this.props.DataDoc, dxf, width)}
             </div>;
         });
     }
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 7fb17c788..25b526168 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -521,8 +521,7 @@ export namespace Doc {
             console.log("No, no, no!");
             return { layout: childDoc, data: childDoc };
         }
-        const existingResolvedDataDoc = childDoc[DataSym] !== Doc.GetProto(childDoc)[DataSym] && childDoc[DataSym];
-        const resolvedDataDoc = existingResolvedDataDoc || (Doc.AreProtosEqual(containerDataDoc, containerDoc) || !containerDataDoc || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField && !childDoc.PARAMS) ? undefined : containerDataDoc);
+        const resolvedDataDoc = (Doc.AreProtosEqual(containerDataDoc, containerDoc) || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField && !childDoc.PARAMS) ? undefined : containerDataDoc);
         return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc, "(" + StrCast(containerDoc.PARAMS) + ")"), data: resolvedDataDoc };
     }
 
-- 
cgit v1.2.3-70-g09d2


From 4859d4e3f5827c3341d43d19a5309d2ec25ab67b Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 1 Apr 2020 17:15:14 -0400
Subject: fixed warnings and some compile errors.  Made a key value layout and
 extened DocumentBox to have a childLayoutKey field

---
 src/client/ClientRecommender.tsx                   |  54 +++++-----
 src/client/cognitive_services/CognitiveServices.ts |  36 +++----
 src/client/documents/Documents.ts                  |   3 +-
 src/client/util/RichTextSchema.tsx                 |  18 ++--
 src/client/views/DocumentButtonBar.tsx             |   2 +-
 src/client/views/EditableView.tsx                  |  22 ++--
 src/client/views/GestureOverlay.tsx                |   8 +-
 src/client/views/GlobalKeyHandler.ts               |   4 +-
 src/client/views/MainView.tsx                      |   2 +
 src/client/views/RecommendationsBox.tsx            |  16 +--
 src/client/views/TemplateMenu.tsx                  |   8 +-
 src/client/views/TouchScrollableMenu.tsx           |   4 +-
 .../views/collections/CollectionDockingView.tsx    |   2 +-
 .../views/collections/CollectionSchemaCells.tsx    |   2 +
 .../views/collections/CollectionSchemaView.tsx     |   8 +-
 .../views/collections/CollectionStackingView.tsx   |   2 +-
 .../CollectionStackingViewFieldColumn.tsx          |   3 +-
 .../views/collections/CollectionStaffView.tsx      |  12 +--
 src/client/views/collections/CollectionSubView.tsx |   3 +-
 .../views/collections/CollectionTimeView.tsx       |   2 +-
 src/client/views/collections/CollectionView.tsx    |   2 +-
 .../views/collections/CollectionViewChromes.tsx    |  10 +-
 .../CollectionFreeFormLinksView.tsx                | 116 ++++++++++-----------
 .../collections/collectionFreeForm/MarqueeView.tsx |   4 +-
 src/client/views/nodes/ButtonBox.tsx               |   2 +-
 .../views/nodes/ContentFittingDocumentView.tsx     |   2 +
 src/client/views/nodes/DocumentBox.tsx             |   3 +-
 src/client/views/nodes/DocumentContentsView.tsx    |  24 +++--
 src/client/views/nodes/KeyValuePair.tsx            |   2 +
 src/client/views/nodes/RadialMenuItem.tsx          |  30 +++---
 src/client/views/nodes/ScreenshotBox.tsx           |   2 +-
 src/client/views/nodes/WebBox.tsx                  |   2 +-
 src/client/views/pdf/PDFViewer.tsx                 |   2 +-
 src/client/views/webcam/DashWebRTCVideo.tsx        |   8 +-
 src/mobile/MobileInterface.tsx                     |   2 +
 src/new_fields/Doc.ts                              |   4 +-
 src/new_fields/util.ts                             |   2 +-
 .../Session/agents/applied_session_agent.ts        |   2 +-
 src/server/DashSession/Session/agents/monitor.ts   |   2 +-
 .../Session/agents/promisified_ipc_manager.ts      |   6 +-
 src/server/Websocket/Websocket.ts                  |   8 +-
 src/server/database.ts                             |   2 +-
 src/server/server_Initialization.ts                |   2 +-
 43 files changed, 232 insertions(+), 218 deletions(-)

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

diff --git a/src/client/ClientRecommender.tsx b/src/client/ClientRecommender.tsx
index 0e67a6e57..537e331ab 100644
--- a/src/client/ClientRecommender.tsx
+++ b/src/client/ClientRecommender.tsx
@@ -69,7 +69,7 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
      */
 
     private distance(vector1: number[], vector2: number[], metric: string = "cosine") {
-        assert(vector1.length === vector2.length, "Vectors are not the same length");
+        // assert(vector1.length === vector2.length, "Vectors are not the same length");
         let similarity: number;
         switch (metric) {
             case "cosine":
@@ -113,7 +113,7 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
             }
         }
         );
-        let doclist = Array.from(ClientRecommender.Instance.docVectors);
+        const doclist = Array.from(ClientRecommender.Instance.docVectors);
         if (distance_metric === "euclidian") {
             doclist.sort((a: RecommenderDocument, b: RecommenderDocument) => a.score - b.score);
         }
@@ -169,12 +169,12 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
      */
 
     generateMetadata = async (dataDoc: Doc, extDoc: Doc, threshold: Confidence = Confidence.Excellent) => {
-        let converter = (results: any) => {
-            let tagDoc = new Doc;
-            let tagsList = new List();
+        const converter = (results: any) => {
+            const tagDoc = new Doc;
+            const tagsList = new List();
             results.tags.map((tag: Tag) => {
                 tagsList.push(tag.name);
-                let sanitized = tag.name.replace(" ", "_");
+                const sanitized = tag.name.replace(" ", "_");
                 tagDoc[sanitized] = ComputedField.MakeFunction(`(${tag.confidence} >= this.confidence) ? ${tag.confidence} : "${ComputedField.undefined}"`);
             });
             extDoc.generatedTags = tagsList;
@@ -193,7 +193,7 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
      */
 
     private url(dataDoc: Doc) {
-        let data = Cast(Doc.GetProto(dataDoc)[fieldkey], ImageField);
+        const data = Cast(Doc.GetProto(dataDoc)[fieldkey], ImageField);
         return data ? data.url.href : undefined;
     }
 
@@ -215,14 +215,14 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
             }
         }
         else {
-            let fielddata = Cast(dataDoc.data, RichTextField);
-            fielddata ? data = fielddata[ToPlainText]() : data = "";
+            const fielddata = Cast(dataDoc.data, RichTextField, null);
+            data = fielddata?.Text || "";
         }
 
         // STEP 2. Upon receiving response from Text Cognitive Services, do additional processing on keywords.
         // Currently we are still using Cognitive Services for internal recommendations, but in the future this might not be necessary. 
 
-        let converter = async (results: any, data: string, isImage: boolean = false) => {
+        const converter = async (results: any, data: string, isImage: boolean = false) => {
             let keyterms = new List<string>(); // raw keywords
             let kp_string: string = ""; // keywords*frequency concatenated into a string. input into TF
             let highKP: string[] = [""]; // most frequent keyphrase
@@ -237,7 +237,7 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
             }
             else { // text processing
                 results.documents.forEach((doc: any) => {
-                    let keyPhrases = doc.keyPhrases; // returned by Cognitive Services
+                    const keyPhrases = doc.keyPhrases; // returned by Cognitive Services
                     keyPhrases.map((kp: string) => {
                         keyterms.push(kp);
                         const frequency = this.countFrequencies(kp, data); // frequency of keyphrase in paragraph
@@ -308,10 +308,10 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
      */
 
     private countFrequencies(keyphrase: string, paragraph: string) {
-        let data = paragraph.split(/ |\n/); // splits by new lines and spaces
-        let kp_array = keyphrase.split(" ");
-        let num_keywords = kp_array.length;
-        let par_length = data.length;
+        const data = paragraph.split(/ |\n/); // splits by new lines and spaces
+        const kp_array = keyphrase.split(" ");
+        const num_keywords = kp_array.length;
+        const par_length = data.length;
         let frequency = 0;
         // slides keyphrase windows across paragraph and checks if it matches with corresponding paragraph slice
         for (let i = 0; i <= par_length - num_keywords; i++) {
@@ -353,8 +353,8 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
 
     bingWebSearch = async (query: string) => {
         const converter = async (results: any) => {
-            let title_vals: string[] = [];
-            let url_vals: string[] = [];
+            const title_vals: string[] = [];
+            const url_vals: string[] = [];
             results.webPages.value.forEach((doc: any) => {
                 title_vals.push(doc.name);
                 url_vals.push(doc.url);
@@ -369,23 +369,23 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
      */
 
     arxivrequest = async (query: string) => {
-        let xhttp = new XMLHttpRequest();
-        let serveraddress = "http://export.arxiv.org/api";
+        const xhttp = new XMLHttpRequest();
+        const serveraddress = "http://export.arxiv.org/api";
         const maxresults = 5;
-        let endpoint = serveraddress + "/query?search_query=all:" + query + "&start=0&max_results=" + maxresults.toString();
-        let promisified = (resolve: any, reject: any) => {
+        const endpoint = serveraddress + "/query?search_query=all:" + query + "&start=0&max_results=" + maxresults.toString();
+        const promisified = (resolve: any, reject: any) => {
             xhttp.onreadystatechange = function () {
                 if (this.readyState === 4) {
-                    let result = xhttp.response;
-                    let xml = xhttp.responseXML;
+                    const result = xhttp.response;
+                    const xml = xhttp.responseXML;
                     console.log("arXiv Result: ", xml);
                     switch (this.status) {
                         case 200:
-                            let title_vals: string[] = [];
-                            let url_vals: string[] = [];
+                            const title_vals: string[] = [];
+                            const url_vals: string[] = [];
                             //console.log(result);
                             if (xml) {
-                                let titles = xml.getElementsByTagName("title");
+                                const titles = xml.getElementsByTagName("title");
                                 let counter = 1;
                                 if (titles && titles.length > 1) {
                                     while (counter <= maxresults) {
@@ -394,7 +394,7 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
                                         counter++;
                                     }
                                 }
-                                let ids = xml.getElementsByTagName("id");
+                                const ids = xml.getElementsByTagName("id");
                                 counter = 1;
                                 if (ids && ids.length > 1) {
                                     while (counter <= maxresults) {
diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts
index 542ccf04d..3f3726621 100644
--- a/src/client/cognitive_services/CognitiveServices.ts
+++ b/src/client/cognitive_services/CognitiveServices.ts
@@ -208,7 +208,7 @@ export namespace CognitiveServices {
                     results.recognitionUnits && (results = results.recognitionUnits);
                 }
                 return results;
-            }
+            };
         }
 
         export interface AzureStrokeData {
@@ -232,13 +232,13 @@ export namespace CognitiveServices {
                 return data;
             },
             requester: async (apiKey: string, query: string) => {
-                let xhttp = new XMLHttpRequest();
-                let serverAddress = "https://api.cognitive.microsoft.com";
-                let endpoint = serverAddress + '/bing/v5.0/search?q=' + encodeURIComponent(query);
-                let promisified = (resolve: any, reject: any) => {
+                const xhttp = new XMLHttpRequest();
+                const serverAddress = "https://api.cognitive.microsoft.com";
+                const endpoint = serverAddress + '/bing/v5.0/search?q=' + encodeURIComponent(query);
+                const promisified = (resolve: any, reject: any) => {
                     xhttp.onreadystatechange = function () {
                         if (this.readyState === 4) {
-                            let result = xhttp.responseText;
+                            const result = xhttp.responseText;
                             switch (this.status) {
                                 case 200:
                                     return resolve(result);
@@ -266,7 +266,7 @@ export namespace CognitiveServices {
 
         export namespace Appliers {
             export const analyzer = async (query: string, converter: BingConverter) => {
-                let results = await ExecuteQuery(Service.Bing, Manager, query);
+                const results = await ExecuteQuery(Service.Bing, Manager, query);
                 console.log("Bing results: ", results);
                 const { title_vals, url_vals } = await converter(results);
                 return { title_vals, url_vals };
@@ -281,13 +281,13 @@ export namespace CognitiveServices {
                 return data;
             },
             requester: async (apiKey: string, query: string) => {
-                let xhttp = new XMLHttpRequest();
-                let serverAddress = "https://babel.hathitrust.org/cgi/htd/​";
-                let endpoint = serverAddress + '/bing/v5.0/search?q=' + encodeURIComponent(query);
-                let promisified = (resolve: any, reject: any) => {
+                const xhttp = new XMLHttpRequest();
+                const serverAddress = "https://babel.hathitrust.org/cgi/htd/​";
+                const endpoint = serverAddress + '/bing/v5.0/search?q=' + encodeURIComponent(query);
+                const promisified = (resolve: any, reject: any) => {
                     xhttp.onreadystatechange = function () {
                         if (this.readyState === 4) {
-                            let result = xhttp.responseText;
+                            const result = xhttp.responseText;
                             switch (this.status) {
                                 case 200:
                                     return resolve(result);
@@ -315,7 +315,7 @@ export namespace CognitiveServices {
 
         export namespace Appliers {
             export const analyzer = async (query: string, converter: BingConverter) => {
-                let results = await ExecuteQuery(Service.Bing, Manager, query);
+                const results = await ExecuteQuery(Service.Bing, Manager, query);
                 console.log("Bing results: ", results);
                 const { title_vals, url_vals } = await converter(results);
                 return { title_vals, url_vals };
@@ -337,9 +337,9 @@ export namespace CognitiveServices {
                 });
             },
             requester: async (apiKey: string, body: string, service: Service) => {
-                let serverAddress = "https://eastus.api.cognitive.microsoft.com";
-                let endpoint = serverAddress + "/text/analytics/v2.1/keyPhrases";
-                let sampleBody = {
+                const serverAddress = "https://eastus.api.cognitive.microsoft.com";
+                const endpoint = serverAddress + "/text/analytics/v2.1/keyPhrases";
+                const sampleBody = {
                     "documents": [
                         {
                             "language": "en",
@@ -348,7 +348,7 @@ export namespace CognitiveServices {
                         }
                     ]
                 };
-                let actualBody = body;
+                const actualBody = body;
                 const options = {
                     uri: endpoint,
                     body: actualBody,
@@ -368,7 +368,7 @@ export namespace CognitiveServices {
                 console.log("vectorizing...");
                 //keyterms = ["father", "king"];
 
-                let args = { method: 'POST', uri: Utils.prepend("/recommender"), body: { keyphrases: keyterms }, json: true };
+                const args = { method: 'POST', uri: Utils.prepend("/recommender"), body: { keyphrases: keyterms }, json: true };
                 await requestPromise.post(args).then(async (wordvecs) => {
                     if (wordvecs) {
                         const indices = Object.keys(wordvecs);
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index dbea8062e..96425ba30 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -266,7 +266,7 @@ export namespace Docs {
                 options: { _width: 40, _height: 40, borderRounding: "100%" },
             }],
             [DocumentType.RECOMMENDATION, {
-                layout: { view: RecommendationsBox },
+                layout: { view: RecommendationsBox, dataField: data },
                 options: { width: 200, height: 200 },
             }],
             [DocumentType.WEBCAM, {
@@ -365,6 +365,7 @@ export namespace Docs {
             const options = { title, type, baseProto: true, ...defaultOptions, ...(template.options || {}) };
             options.layout = layout.view.LayoutString(layout.dataField);
             const doc = Doc.assign(new Doc(prototypeId, true), { layoutKey: "layout", ...options });
+            doc.layout_keyValue = KeyValueBox.LayoutString("");
             return doc;
         }
 
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index a2fb7c11b..81ab95ff5 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -810,7 +810,7 @@ export class DashDocView {
                 this._dashSpan.style.height = this._outer.style.height = Math.max(20, dim[1]) + "px";
                 this._outer.style.border = "1px solid " + StrCast(finalLayout.color, (Cast(Doc.UserDoc().activeWorkspace, Doc, null).darkScheme ? "dimGray" : "lightGray"));
             }, { fireImmediately: true });
-            let doReactRender = (finalLayout: Doc, resolvedDataDoc: Doc) => {
+            const doReactRender = (finalLayout: Doc, resolvedDataDoc: Doc) => {
                 ReactDOM.unmountComponentAtNode(this._dashSpan);
                 ReactDOM.render(<DocumentView
                     Document={finalLayout}
@@ -844,7 +844,7 @@ export class DashDocView {
                         console.log(e);
                     }
                 }
-            }
+            };
             this._renderDisposer?.();
             this._renderDisposer = reaction(() => {
                 if (!Doc.AreProtosEqual(finalLayout, dashDoc)) {
@@ -939,7 +939,7 @@ export class DashFieldView {
         this._fieldCheck.style.backgroundColor = "rgba(155, 155, 155, 0.24)";
         this._fieldCheck.onchange = function (e: any) {
             self._dashDoc![self._fieldKey] = e.target.checked;
-        }
+        };
 
         this._fieldSpan = document.createElement("div");
         this._fieldSpan.id = Utils.GenerateGuid();
@@ -1095,12 +1095,12 @@ export class FootnoteView {
                     "Mod-y": () => redo(this.outerView.state, this.outerView.dispatch),
                     "Mod-b": toggleMark(schema.marks.strong)
                 }),
-                new Plugin({
-                    view(newView) {
-                        // TODO -- make this work with RichTextMenu
-                        // return FormattedTextBox.getToolTip(newView);
-                    }
-                })
+                    // new Plugin({
+                    //     view(newView) {
+                    //         // TODO -- make this work with RichTextMenu
+                    //         // return FormattedTextBox.getToolTip(newView);
+                    //     }
+                    // })
                 ],
 
             }),
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index e673189f9..c6fb9ad0b 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -39,7 +39,7 @@ library.add(faCheckCircle);
 library.add(faCloudUploadAlt);
 library.add(faSyncAlt);
 library.add(faShare);
-library.add(faPhotoVideo)
+library.add(faPhotoVideo);
 
 const cloud: IconProp = "cloud-upload-alt";
 const fetch: IconProp = "sync-alt";
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 4a27425e8..2219966e5 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -4,10 +4,7 @@ import { observer } from 'mobx-react';
 import * as Autosuggest from 'react-autosuggest';
 import { ObjectField } from '../../new_fields/ObjectField';
 import { SchemaHeaderField } from '../../new_fields/SchemaHeaderField';
-import { ContextMenu } from './ContextMenu';
-import { ContextMenuProps } from './ContextMenuItem';
 import "./EditableView.scss";
-import { CollectionTreeView } from './collections/CollectionTreeView';
 
 export interface EditableProps {
     /**
@@ -88,12 +85,12 @@ export class EditableView extends React.Component<EditableProps> {
     onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
         if (e.key === "Tab") {
             e.stopPropagation();
-            this.finalizeEdit(e.currentTarget.value, e.shiftKey);
+            this.finalizeEdit(e.currentTarget.value, e.shiftKey, false);
             this.props.OnTab && this.props.OnTab(e.shiftKey);
         } else if (e.key === "Enter") {
             e.stopPropagation();
             if (!e.ctrlKey) {
-                this.finalizeEdit(e.currentTarget.value, e.shiftKey);
+                this.finalizeEdit(e.currentTarget.value, e.shiftKey, false);
             } else if (this.props.OnFillDown) {
                 this.props.OnFillDown(e.currentTarget.value);
                 this._editing = false;
@@ -123,10 +120,17 @@ export class EditableView extends React.Component<EditableProps> {
     }
 
     @action
-    private finalizeEdit(value: string, shiftDown: boolean) {
-        this._editing = false;
+    private finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean) {
         if (this.props.SetValue(value, shiftDown)) {
+            this._editing = false;
+            this.props.isEditingCallback?.(false);
+        } else {
+            this._editing = false;
             this.props.isEditingCallback?.(false);
+            !lostFocus && setTimeout(action(() => {
+                this._editing = true;
+                this.props.isEditingCallback?.(true);
+            }), 0);
         }
     }
 
@@ -151,7 +155,7 @@ export class EditableView extends React.Component<EditableProps> {
                         className: "editableView-input",
                         onKeyDown: this.onKeyDown,
                         autoFocus: true,
-                        onBlur: e => this.finalizeEdit(e.currentTarget.value, false),
+                        onBlur: e => this.finalizeEdit(e.currentTarget.value, false, true),
                         onPointerDown: this.stopPropagation,
                         onClick: this.stopPropagation,
                         onPointerUp: this.stopPropagation,
@@ -163,7 +167,7 @@ export class EditableView extends React.Component<EditableProps> {
                     defaultValue={this.props.GetValue()}
                     onKeyDown={this.onKeyDown}
                     autoFocus={true}
-                    onBlur={e => this.finalizeEdit(e.currentTarget.value, false)}
+                    onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true)}
                     onPointerDown={this.stopPropagation} onClick={this.stopPropagation} onPointerUp={this.stopPropagation}
                     style={{ display: this.props.display, fontSize: this.props.fontSize }}
                 />;
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 1eff58948..ea60907f6 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -165,7 +165,7 @@ export default class GestureOverlay extends Touchable {
                 this._holdTimer = setTimeout(() => {
                     console.log("hold");
                     const target = document.elementFromPoint(te.changedTouches.item(0).clientX, te.changedTouches.item(0).clientY);
-                    let pt: any = te.touches[te.touches.length - 1];
+                    const pt: any = te.touches[te.touches.length - 1];
                     if (nts.nt.length === 1 && pt.radiusX > 1 && pt.radiusY > 1) {
                         target?.dispatchEvent(
                             new CustomEvent<InteractionUtils.MultiTouchEvent<React.TouchEvent>>("dashOnTouchHoldStart",
@@ -589,7 +589,7 @@ export default class GestureOverlay extends Touchable {
                             for (const wR of wordResults) {
                                 console.log(wR);
                                 if (wR?.recognizedText) {
-                                    possibilities.push(wR?.recognizedText)
+                                    possibilities.push(wR?.recognizedText);
                                 }
                                 possibilities.push(...wR?.alternates?.map((a: any) => a.recognizedString));
                             }
@@ -743,16 +743,16 @@ export default class GestureOverlay extends Touchable {
                 {this.elements}
 
                 <div className="clipboardDoc-cont" style={{
-                    transform: `translate(${this._thumbX}px, ${(this._thumbY ?? 0) - this.height}px)`,
                     height: this.height,
                     width: this.height,
                     pointerEvents: this._clipboardDoc ? "unset" : "none",
                     touchAction: this._clipboardDoc ? "unset" : "none",
+                    transform: `translate(${this._thumbX}px, ${(this._thumbY || 0) - this.height} px)`,
                 }}>
                     {this._clipboardDoc}
                 </div>
                 <div className="filter-cont" style={{
-                    transform: `translate(${this._thumbX}px, ${(this._thumbY ?? 0) - this.height}px)`,
+                    transform: `translate(${this._thumbX}px, ${(this._thumbY || 0) - this.height}px)`,
                     height: this.height,
                     width: this.height,
                     pointerEvents: "none",
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index b59ee7a87..52801b570 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -106,8 +106,8 @@ export default class KeyManager {
     });
 
     private shift = async (keyname: string) => {
-        let stopPropagation = false;
-        let preventDefault = false;
+        const stopPropagation = false;
+        const preventDefault = false;
 
         switch (keyname) {
             // case "~":
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index a81e0cc2c..8d9be5980 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -521,7 +521,9 @@ export class MainView extends React.Component {
                     DataDoc={undefined}
                     LibraryPath={emptyPath}
                     fieldKey={"data"}
+                    dropAction={"alias"}
                     annotationsKey={""}
+                    bringToFront={emptyFunction}
                     select={emptyFunction}
                     active={returnFalse}
                     isSelected={returnFalse}
diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
index 262226bac..5ebba0abb 100644
--- a/src/client/views/RecommendationsBox.tsx
+++ b/src/client/views/RecommendationsBox.tsx
@@ -6,7 +6,7 @@ import "./RecommendationsBox.scss";
 import { Doc, DocListCast, WidthSym, HeightSym } from "../../new_fields/Doc";
 import { DocumentIcon } from "./nodes/DocumentIcon";
 import { StrCast, NumCast } from "../../new_fields/Types";
-import { returnFalse, emptyFunction, returnEmptyString, returnOne } from "../../Utils";
+import { returnFalse, emptyFunction, returnEmptyString, returnOne, emptyPath } from "../../Utils";
 import { Transform } from "../util/Transform";
 import { ObjectField } from "../../new_fields/ObjectField";
 import { DocumentView } from "./nodes/DocumentView";
@@ -31,7 +31,7 @@ library.add(faBullseye, faLink);
 @observer
 export class RecommendationsBox extends React.Component<FieldViewProps> {
 
-    public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(RecommendationsBox, fieldKey); }
+    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(RecommendationsBox, fieldKey); }
 
     // @observable private _display: boolean = false;
     @observable private _pageX: number = 0;
@@ -48,17 +48,17 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
 
     @action
     private DocumentIcon(doc: Doc) {
-        let layoutresult = StrCast(doc.type);
+        const layoutresult = StrCast(doc.type);
         let renderDoc = doc;
         //let box: number[] = [];
         if (layoutresult.indexOf(DocumentType.COL) !== -1) {
             renderDoc = Doc.MakeDelegate(renderDoc);
         }
-        let returnXDimension = () => 150;
-        let returnYDimension = () => 150;
-        let scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension());
+        const returnXDimension = () => 150;
+        const returnYDimension = () => 150;
+        const scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension());
         //let scale = () => 1;
-        let newRenderDoc = Doc.MakeAlias(renderDoc); ///   newRenderDoc -> renderDoc -> render"data"Doc -> TextProt
+        const newRenderDoc = Doc.MakeAlias(renderDoc); ///   newRenderDoc -> renderDoc -> render"data"Doc -> TextProt
         newRenderDoc.height = NumCast(this.props.Document.documentIconHeight);
         newRenderDoc.autoHeight = false;
         const docview = <div>
@@ -66,8 +66,8 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
                 fitToBox={StrCast(doc.type).indexOf(DocumentType.COL) !== -1}
                 Document={newRenderDoc}
                 addDocument={returnFalse}
+                LibraryPath={emptyPath}
                 removeDocument={returnFalse}
-                ruleProvider={undefined}
                 ScreenToLocalTransform={Transform.Identity}
                 addDocTab={returnFalse}
                 pinToPres={returnFalse}
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 83dbd3db3..996928cca 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -114,7 +114,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
         const templateName = StrCast(firstDoc.layoutKey, "layout").replace("layout_", "");
         const noteTypesDoc = Cast(Doc.UserDoc().noteTypes, Doc, null);
         const noteTypes = DocListCast(noteTypesDoc?.data);
-        const addedTypes = DocListCast(Cast(Doc.UserDoc().templateButtons, Doc, null)?.data)
+        const addedTypes = DocListCast(Cast(Doc.UserDoc().templateButtons, Doc, null)?.data);
         const layout = Doc.Layout(firstDoc);
         const templateMenu: Array<JSX.Element> = [];
         this.props.templates.forEach((checked, template) =>
@@ -170,8 +170,8 @@ Scripting.addGlobal(function switchView(doc: Doc, template: Doc) {
     if (template.dragFactory) {
         template = Cast(template.dragFactory, Doc, null);
     }
-    let templateTitle = StrCast(template?.title);
-    return templateTitle && DocumentView.makeCustomViewClicked(doc, undefined, Docs.Create.FreeformDocument, templateTitle, template)
+    const templateTitle = StrCast(template?.title);
+    return templateTitle && DocumentView.makeCustomViewClicked(doc, undefined, Docs.Create.FreeformDocument, templateTitle, template);
 });
 
 Scripting.addGlobal(function templateIsUsed(templateDoc: Doc, firstDocTitlte: string) {
@@ -180,4 +180,4 @@ Scripting.addGlobal(function templateIsUsed(templateDoc: Doc, firstDocTitlte: st
     const template = StrCast(templateDoc.dragFactory ? Cast(templateDoc.dragFactory, Doc, null)?.title : templateDoc.title);
     return StrCast(firstDoc.layoutKey) === "layout_" + template ? 'check' : 'unchecked';
     // return SelectionManager.SelectedDocuments().some(view => StrCast(view.props.Document.layoutKey) === "layout_" + template) ? 'check' : 'unchecked'
-})
\ No newline at end of file
+});
\ No newline at end of file
diff --git a/src/client/views/TouchScrollableMenu.tsx b/src/client/views/TouchScrollableMenu.tsx
index 4bda0818e..969605be9 100644
--- a/src/client/views/TouchScrollableMenu.tsx
+++ b/src/client/views/TouchScrollableMenu.tsx
@@ -44,7 +44,7 @@ export default class TouchScrollableMenu extends React.Component<TouchScrollable
                 <div className="shadow" style={{ height: `calc(100% - 25px - ${this.selectedIndex * 25}px)` }}>
                 </div>
             </div>
-        )
+        );
     }
 }
 
@@ -54,6 +54,6 @@ export class TouchScrollableMenuItem extends React.Component<TouchScrollableMenu
             <div className="menuItem-cont" onClick={this.props.onClick}>
                 {this.props.text}
             </div>
-        )
+        );
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 2ee39bc0d..4e1e76f39 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -513,7 +513,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
                         dragData.dropAction = doc.dropAction as dropActionType;
                         DragManager.StartDocumentDrag([gearSpan], dragData, e.clientX, e.clientY);
                     }
-                }
+                };
                 let rendered = false;
                 tab.buttonDisposer = reaction(() => ((view: Opt<DocumentView>) => view ? [view] : [])(DocumentManager.Instance.getDocumentView(doc)),
                     (views) => {
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 79b5d7bb7..f124fe21b 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -157,6 +157,8 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             Document: this.props.rowProps.original,
             DataDoc: this.props.rowProps.original,
             LibraryPath: [],
+            dropAction: "alias",
+            bringToFront: emptyFunction,
             fieldKey: this.props.rowProps.column.id as string,
             ContainingCollectionView: this.props.CollectionView,
             ContainingCollectionDoc: this.props.CollectionView && this.props.CollectionView.props.Document,
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index a4502cced..981438513 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -51,8 +51,7 @@ const columnTypes: Map<string, ColumnType> = new Map([
 
 @observer
 export class CollectionSchemaView extends CollectionSubView(doc => doc) {
-    private _mainCont?: HTMLDivElement;
-    private _startPreviewWidth = 0;
+    private _previewCont?: HTMLDivElement;
     private DIVIDER_WIDTH = 4;
 
     @observable previewDoc: Doc | undefined = undefined;
@@ -64,7 +63,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
     @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); }
 
     private createTarget = (ele: HTMLDivElement) => {
-        this._mainCont = ele;
+        this._previewCont = ele;
         super.CreateDropTarget(ele);
     }
 
@@ -81,12 +80,11 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
     }
 
     onDividerDown = (e: React.PointerEvent) => {
-        this._startPreviewWidth = this.previewWidth();
         setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, action(() => this.toggleExpander()));
     }
     @action
     onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => {
-        const nativeWidth = this._mainCont!.getBoundingClientRect();
+        const nativeWidth = this._previewCont!.getBoundingClientRect();
         const minWidth = 40;
         const maxWidth = 1000;
         const movedWidth = this.props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0];
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 086e0842e..076dd3629 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -106,7 +106,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                 fields.delete(header);
                 sectionHeaders.splice(sectionHeaders.indexOf(header), 1);
                 changed = true;
-            })
+            });
         }
         changed && setTimeout(action(() => { if (this.sectionHeaders) { this.sectionHeaders.length = 0; this.sectionHeaders.push(...sectionHeaders); } }), 0);
         return fields;
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 646b433bf..0a48c95e4 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -131,7 +131,8 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         const maxHeading = this.props.docList.reduce((maxHeading, doc) => NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0);
         const heading = maxHeading === 0 || this.props.docList.length === 0 ? 1 : maxHeading === 1 ? 2 : 3;
         newDoc.heading = heading;
-        return this.props.parent.props.addDocument(newDoc);
+        this.props.parent.props.addDocument(newDoc);
+        return false;
     }
 
     @action
diff --git a/src/client/views/collections/CollectionStaffView.tsx b/src/client/views/collections/CollectionStaffView.tsx
index 8c7e113b2..5b9a69bf7 100644
--- a/src/client/views/collections/CollectionStaffView.tsx
+++ b/src/client/views/collections/CollectionStaffView.tsx
@@ -1,22 +1,20 @@
 import { CollectionSubView } from "./CollectionSubView";
-import { Transform } from "../../util/Transform";
 import React = require("react");
 import { computed, action, IReactionDisposer, reaction, runInAction, observable } from "mobx";
-import { Doc } from "../../../new_fields/Doc";
 import { NumCast } from "../../../new_fields/Types";
 import "./CollectionStaffView.scss";
 import { observer } from "mobx-react";
 
 @observer
 export class CollectionStaffView extends CollectionSubView(doc => doc) {
-    private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(0, -this._mainCont.current!.scrollTop);
-    private _mainCont = React.createRef<HTMLDivElement>();
     private _reactionDisposer: IReactionDisposer | undefined;
     @observable private _staves = NumCast(this.props.Document.staves);
 
+    componentWillUnmount() {
+        this._reactionDisposer?.();
+    }
     componentDidMount = () => {
-        this._reactionDisposer = reaction(
-            () => NumCast(this.props.Document.staves),
+        this._reactionDisposer = reaction(() => NumCast(this.props.Document.staves),
             (staves) => runInAction(() => this._staves = staves)
         );
 
@@ -47,7 +45,7 @@ export class CollectionStaffView extends CollectionSubView(doc => doc) {
     }
 
     render() {
-        return <div className="collectionStaffView" ref={this._mainCont}>
+        return <div className="collectionStaffView">
             {this.staves}
             {this.addStaffButton}
         </div>;
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 88cfde0b6..70927cf22 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,5 +1,4 @@
 import { action, computed, IReactionDisposer, reaction } from "mobx";
-import * as rp from 'request-promise';
 import CursorField from "../../../new_fields/CursorField";
 import { Doc, DocListCast, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
@@ -107,7 +106,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
         get childLayoutPairs(): { layout: Doc; data: Doc; }[] {
             const { Document, DataDoc } = this.props;
             const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.annotationsKey ? DataDoc : undefined, doc)).filter(pair => pair.layout);
-            return validPairs.map(({ data, layout }) => ({ data, layout: layout! })); // this mapping is a bit of a hack to coerce types
+            return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types
         }
         get childDocList() {
             return Cast(this.dataField, listSpec(Doc));
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 64832506b..0d2207b27 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -146,7 +146,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
                 back
             </button>
             <EditableView {...newEditableViewProps} display={"inline"} menuCallback={this.menuCallback} />
-        </div>
+        </div>;
     }
 
     render() {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index edb9fd930..b6ce2f3a9 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -299,7 +299,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
     get childLayoutPairs(): { layout: Doc; data: Doc; }[] {
         const { Document, DataDoc } = this.props;
         const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, DataDoc, doc)).filter(pair => pair.layout);
-        return validPairs.map(({ data, layout }) => ({ data, layout: layout! })); // this mapping is a bit of a hack to coerce types
+        return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types
     }
     get childDocList() {
         return Cast(this.dataField, listSpec(Doc));
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 960c6554e..2d565d9db 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -267,10 +267,10 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
         const collapsed = this.props.CollectionView.props.Document._chromeStatus !== "enabled";
         if (collapsed) return null;
         switch (this.props.type) {
-            case CollectionViewType.Stacking: return (<CollectionStackingViewChrome key="collchrome" CollectionView={this.props.CollectionView} type={this.props.type} />);
-            case CollectionViewType.Schema: return (<CollectionSchemaViewChrome key="collchrome" CollectionView={this.props.CollectionView} type={this.props.type} />);
-            case CollectionViewType.Tree: return (<CollectionTreeViewChrome key="collchrome" CollectionView={this.props.CollectionView} type={this.props.type} />);
-            case CollectionViewType.Masonry: return (<CollectionStackingViewChrome key="collchrome" CollectionView={this.props.CollectionView} type={this.props.type} />);
+            case CollectionViewType.Stacking: return (<CollectionStackingViewChrome key="collchrome" PanelWidth={this.props.PanelWidth} CollectionView={this.props.CollectionView} type={this.props.type} />);
+            case CollectionViewType.Schema: return (<CollectionSchemaViewChrome key="collchrome" PanelWidth={this.props.PanelWidth} CollectionView={this.props.CollectionView} type={this.props.type} />);
+            case CollectionViewType.Tree: return (<CollectionTreeViewChrome key="collchrome" PanelWidth={this.props.PanelWidth} CollectionView={this.props.CollectionView} type={this.props.type} />);
+            case CollectionViewType.Masonry: return (<CollectionStackingViewChrome key="collchrome" PanelWidth={this.props.PanelWidth} CollectionView={this.props.CollectionView} type={this.props.type} />);
             default: return null;
         }
     }
@@ -355,7 +355,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                 immediate: (source: Doc[]) => Doc.setChildLayout(this.target, source?.[0]),
                 initialize: emptyFunction,
             };
-            DragManager.StartButtonDrag([this._viewRef.current!], c.script, c.title,
+            DragManager.StartButtonDrag([this._viewRef.current!], c.script, StrCast(c.title),
                 { target: this.props.CollectionView.props.Document }, c.params, c.initialize, e.clientX, e.clientY);
             return true;
         }, emptyFunction, emptyFunction);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index a1ec0daef..49ca024a2 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -1,4 +1,4 @@
-import { computed, IReactionDisposer } from "mobx";
+import { computed } from "mobx";
 import { observer } from "mobx-react";
 import { Doc } from "../../../../new_fields/Doc";
 import { Id } from "../../../../new_fields/FieldSymbols";
@@ -10,67 +10,9 @@ import React = require("react");
 import { Utils, emptyFunction } from "../../../../Utils";
 import { SelectionManager } from "../../../util/SelectionManager";
 import { DocumentType } from "../../../documents/DocumentTypes";
-import { StrCast } from "../../../../new_fields/Types";
 
 @observer
 export class CollectionFreeFormLinksView extends React.Component {
-
-    _brushReactionDisposer?: IReactionDisposer;
-    componentDidMount() {
-        // this._brushReactionDisposer = reaction(
-        //     () => {
-        //         let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
-        //         return { doclist: doclist ? doclist : [], xs: doclist.map(d => d.x) };
-        //     },
-        //     () => {
-        //         let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
-        //         let views = doclist ? doclist.filter(doc => StrCast(doc.backgroundLayout).indexOf("istogram") !== -1) : [];
-        //         views.forEach((dstDoc, i) => {
-        //             views.forEach((srcDoc, j) => {
-        //                 let dstTarg = dstDoc;
-        //                 let srcTarg = srcDoc;
-        //                 let x1 = NumCast(srcDoc.x);
-        //                 let x2 = NumCast(dstDoc.x);
-        //                 let x1w = NumCast(srcDoc.width, -1);
-        //                 let x2w = NumCast(dstDoc.width, -1);
-        //                 if (x1w < 0 || x2w < 0 || i === j) { }
-        //                 else {
-        //                     let findBrush = (field: (Doc | Promise<Doc>)[]) => field.findIndex(brush => {
-        //                         let bdocs = brush instanceof Doc ? Cast(brush.brushingDocs, listSpec(Doc), []) : undefined;
-        //                         return bdocs && bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false;
-        //                     });
-        //                     let brushAction = (field: (Doc | Promise<Doc>)[]) => {
-        //                         let found = findBrush(field);
-        //                         if (found !== -1) {
-        //                             field.splice(found, 1);
-        //                         }
-        //                     };
-        //                     if (Math.abs(x1 + x1w - x2) < 20) {
-        //                         let linkDoc: Doc = new Doc();
-        //                         linkDoc.title = "Histogram Brush";
-        //                         linkDoc.linkDescription = "Brush between " + StrCast(srcTarg.title) + " and " + StrCast(dstTarg.Title);
-        //                         linkDoc.brushingDocs = new List([dstTarg, srcTarg]);
-
-        //                         brushAction = (field: (Doc | Promise<Doc>)[]) => {
-        //                             if (findBrush(field) === -1) {
-        //                                 field.push(linkDoc);
-        //                             }
-        //                         };
-        //                     }
-        //                     if (dstTarg.brushingDocs === undefined) dstTarg.brushingDocs = new List<Doc>();
-        //                     if (srcTarg.brushingDocs === undefined) srcTarg.brushingDocs = new List<Doc>();
-        //                     let dstBrushDocs = Cast(dstTarg.brushingDocs, listSpec(Doc), []);
-        //                     let srcBrushDocs = Cast(srcTarg.brushingDocs, listSpec(Doc), []);
-        //                     brushAction(dstBrushDocs);
-        //                     brushAction(srcBrushDocs);
-        //                 }
-        //             });
-        //         });
-        //     });
-    }
-    componentWillUnmount() {
-        this._brushReactionDisposer && this._brushReactionDisposer();
-    }
     @computed
     get uniqueConnections() {
         const connections = DocumentManager.Instance.LinkedDocumentViews.reduce((drawnPairs, connection) => {
@@ -101,4 +43,60 @@ export class CollectionFreeFormLinksView extends React.Component {
             {this.props.children}
         </div>;
     }
+    // _brushReactionDisposer?: IReactionDisposer;
+    // componentDidMount() {
+    //     this._brushReactionDisposer = reaction(
+    //         () => {
+    //             let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
+    //             return { doclist: doclist ? doclist : [], xs: doclist.map(d => d.x) };
+    //         },
+    //         () => {
+    //             let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
+    //             let views = doclist ? doclist.filter(doc => StrCast(doc.backgroundLayout).indexOf("istogram") !== -1) : [];
+    //             views.forEach((dstDoc, i) => {
+    //                 views.forEach((srcDoc, j) => {
+    //                     let dstTarg = dstDoc;
+    //                     let srcTarg = srcDoc;
+    //                     let x1 = NumCast(srcDoc.x);
+    //                     let x2 = NumCast(dstDoc.x);
+    //                     let x1w = NumCast(srcDoc.width, -1);
+    //                     let x2w = NumCast(dstDoc.width, -1);
+    //                     if (x1w < 0 || x2w < 0 || i === j) { }
+    //                     else {
+    //                         let findBrush = (field: (Doc | Promise<Doc>)[]) => field.findIndex(brush => {
+    //                             let bdocs = brush instanceof Doc ? Cast(brush.brushingDocs, listSpec(Doc), []) : undefined;
+    //                             return bdocs && bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false;
+    //                         });
+    //                         let brushAction = (field: (Doc | Promise<Doc>)[]) => {
+    //                             let found = findBrush(field);
+    //                             if (found !== -1) {
+    //                                 field.splice(found, 1);
+    //                             }
+    //                         };
+    //                         if (Math.abs(x1 + x1w - x2) < 20) {
+    //                             let linkDoc: Doc = new Doc();
+    //                             linkDoc.title = "Histogram Brush";
+    //                             linkDoc.linkDescription = "Brush between " + StrCast(srcTarg.title) + " and " + StrCast(dstTarg.Title);
+    //                             linkDoc.brushingDocs = new List([dstTarg, srcTarg]);
+
+    //                             brushAction = (field: (Doc | Promise<Doc>)[]) => {
+    //                                 if (findBrush(field) === -1) {
+    //                                     field.push(linkDoc);
+    //                                 }
+    //                             };
+    //                         }
+    //                         if (dstTarg.brushingDocs === undefined) dstTarg.brushingDocs = new List<Doc>();
+    //                         if (srcTarg.brushingDocs === undefined) srcTarg.brushingDocs = new List<Doc>();
+    //                         let dstBrushDocs = Cast(dstTarg.brushingDocs, listSpec(Doc), []);
+    //                         let srcBrushDocs = Cast(srcTarg.brushingDocs, listSpec(Doc), []);
+    //                         brushAction(dstBrushDocs);
+    //                         brushAction(srcBrushDocs);
+    //                     }
+    //                 });
+    //             });
+    //         });
+    // }
+    // componentWillUnmount() {
+    //     this._brushReactionDisposer?.();
+    // }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 0f94bffd6..276a49570 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -4,7 +4,7 @@ import { Doc, DocListCast, DataSym, WidthSym, HeightSym } from "../../../../new_
 import { InkField, InkData } from "../../../../new_fields/InkField";
 import { List } from "../../../../new_fields/List";
 import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField";
-import { Cast, NumCast, FieldValue } from "../../../../new_fields/Types";
+import { Cast, NumCast, FieldValue, StrCast } from "../../../../new_fields/Types";
 import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils";
 import { Utils } from "../../../../Utils";
 import { Docs, DocUtils } from "../../../documents/Documents";
@@ -107,7 +107,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             });
         } else if (!e.ctrlKey) {
             FormattedTextBox.SelectOnLoadChar = FormattedTextBox.DefaultLayout ? e.key : "";
-            let tbox = Docs.Create.TextDocument("", { _width: 200, _height: 100, x: x, y: y, _autoHeight: true, title: "-typed text-" });
+            const tbox = Docs.Create.TextDocument("", { _width: 200, _height: 100, x: x, y: y, _autoHeight: true, title: "-typed text-" });
             const template = FormattedTextBox.DefaultLayout;
             if (template instanceof Doc) {
                 tbox._width = NumCast(template._width);
diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx
index de0b509eb..f1bf7cfcf 100644
--- a/src/client/views/nodes/ButtonBox.tsx
+++ b/src/client/views/nodes/ButtonBox.tsx
@@ -82,7 +82,7 @@ export class ButtonBox extends DocComponent<FieldViewProps, ButtonDocument>(Butt
                 style={{ boxShadow: this.Document.opacity === 0 ? undefined : StrCast(this.Document.boxShadow, "") }}>
                 <div className="buttonBox-mainButton" style={{
                     background: this.Document.backgroundColor, color: this.Document.color || "inherit",
-                    fontSize: this.Document.fontSize, letterSpacing: this.Document.letterSpacing || "", textTransform: this.Document.textTransform || ""
+                    fontSize: this.Document.fontSize, letterSpacing: this.Document.letterSpacing || "", textTransform: (this.Document.textTransform as any) || ""
                 }} >
                     <div className="buttonBox-mainButtonCenter">
                         {(this.Document.text || this.Document.title)}
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 8632f9c9a..9494a4bc4 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -22,6 +22,7 @@ interface ContentFittingDocumentViewProps {
     childDocs?: Doc[];
     renderDepth: number;
     fitToBox?: boolean;
+    layoutKey?: string;
     dropAction?: dropActionType;
     PanelWidth: () => number;
     PanelHeight: () => number;
@@ -88,6 +89,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         LayoutDoc={this.props.LayoutDoc}
                         LibraryPath={this.props.LibraryPath}
                         fitToBox={this.props.fitToBox}
+                        layoutKey={this.props.layoutKey}
                         dropAction={this.props.dropAction}
                         onClick={this.props.onClick}
                         backgroundColor={this.props.backgroundColor}
diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx
index 978480142..655dc5de2 100644
--- a/src/client/views/nodes/DocumentBox.tsx
+++ b/src/client/views/nodes/DocumentBox.tsx
@@ -117,13 +117,14 @@ export class DocumentBox extends DocAnnotatableComponent<FieldViewProps, DocBoxS
                 DataDocument={undefined}
                 LibraryPath={emptyPath}
                 fitToBox={this.props.fitToBox}
+                layoutKey={StrCast(this.props.Document.childLayoutKey)}
                 addDocument={this.props.addDocument}
                 moveDocument={this.props.moveDocument}
                 removeDocument={this.props.removeDocument}
                 addDocTab={this.props.addDocTab}
                 pinToPres={this.props.pinToPres}
                 getTransform={this.getTransform}
-                renderDepth={this.props.renderDepth + 1} // bcz: need a forceActive prop here ... not the same as renderDepth = 0
+                renderDepth={this.props.renderDepth + 1}
                 PanelWidth={this.pwidth}
                 PanelHeight={this.pheight}
                 focus={this.props.focus}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 8be6ab151..c250da874 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -64,15 +64,18 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
         TraceMobx();
         if (!this.layoutDoc) return "<p>awaiting layout</p>";
         const layout = Cast(this.layoutDoc[StrCast(this.layoutDoc.layoutKey, this.layoutDoc === this.props.Document ? this.props.layoutKey : "layout")], "string");
-        if (layout === undefined) {
-            return this.props.Document.data ?
-                "<FieldView {...props} fieldKey='data' />" :
-                KeyValueBox.LayoutString(this.layoutDoc.proto ? "proto" : "");
-        } else if (typeof layout === "string") {
-            return layout;
-        } else {
-            return "<p>Loading layout</p>";
-        }
+        if (this.props.layoutKey === "layout_keyValue") {
+            return StrCast(this.props.Document.layout_keyValue, KeyValueBox.LayoutString("data"));
+        } else
+            if (layout === undefined) {
+                return this.props.Document.data ?
+                    "<FieldView {...props} fieldKey='data' />" :
+                    KeyValueBox.LayoutString(this.layoutDoc.proto ? "proto" : "");
+            } else if (typeof layout === "string") {
+                return layout;
+            } else {
+                return "<p>Loading layout</p>";
+            }
     }
 
     get dataDoc() {
@@ -81,7 +84,8 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
     }
     get layoutDoc() {
         const params = StrCast(this.props.Document.PARAMS);
-        return Doc.expandTemplateLayout(this.props.LayoutDoc?.() || Doc.Layout(this.props.Document), this.props.Document, params ? "(" + params + ")" : this.props.layoutKey);
+        const template: Doc = this.props.LayoutDoc?.() || Doc.Layout(this.props.Document, this.props.layoutKey ? Cast(this.props.Document[this.props.layoutKey], Doc, null) : undefined);
+        return Doc.expandTemplateLayout(template, this.props.Document, params ? "(" + params + ")" : this.props.layoutKey);
     }
 
     CreateBindings(): JsxBindings {
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 93bda6d02..3d59ea61a 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -61,6 +61,8 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             fieldKey: this.props.keyName,
             isSelected: returnFalse,
             select: emptyFunction,
+            dropAction:"alias",
+            bringToFront:emptyFunction,
             renderDepth: 1,
             active: returnFalse,
             whenActiveChanged: emptyFunction,
diff --git a/src/client/views/nodes/RadialMenuItem.tsx b/src/client/views/nodes/RadialMenuItem.tsx
index fdc732d3f..bd5b3bff4 100644
--- a/src/client/views/nodes/RadialMenuItem.tsx
+++ b/src/client/views/nodes/RadialMenuItem.tsx
@@ -44,12 +44,12 @@ export class RadialMenuItem extends React.Component<RadialMenuProps> {
 
     setcircle() {
         let circlemin = 0;
-        let circlemax = 1
+        let circlemax = 1;
         this.props.min ? circlemin = this.props.min : null;
         this.props.max ? circlemax = this.props.max : null;
         if (document.getElementById("myCanvas") !== null) {
-            var c: any = document.getElementById("myCanvas");
-            let color = "white"
+            const c: any = document.getElementById("myCanvas");
+            let color = "white";
             switch (circlemin % 3) {
                 case 1:
                     color = "#c2c2c5";
@@ -70,38 +70,38 @@ export class RadialMenuItem extends React.Component<RadialMenuProps> {
 
             }
             if (c.getContext) {
-                var ctx = c.getContext("2d");
+                const ctx = c.getContext("2d");
                 ctx.beginPath();
                 ctx.arc(150, 150, 150, (circlemin / circlemax) * 2 * Math.PI, ((circlemin + 1) / circlemax) * 2 * Math.PI);
                 ctx.arc(150, 150, 50, ((circlemin + 1) / circlemax) * 2 * Math.PI, (circlemin / circlemax) * 2 * Math.PI, true);
                 ctx.fillStyle = color;
-                ctx.fill()
+                ctx.fill();
             }
         }
     }
 
     calculatorx() {
         let circlemin = 0;
-        let circlemax = 1
+        let circlemax = 1;
         this.props.min ? circlemin = this.props.min : null;
         this.props.max ? circlemax = this.props.max : null;
-        let avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2;
-        let degrees = 360 * avg;
-        let x = 100 * Math.cos(degrees * Math.PI / 180);
-        let y = -125 * Math.sin(degrees * Math.PI / 180);
+        const avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2;
+        const degrees = 360 * avg;
+        const x = 100 * Math.cos(degrees * Math.PI / 180);
+        const y = -125 * Math.sin(degrees * Math.PI / 180);
         return x;
     }
 
     calculatory() {
 
         let circlemin = 0;
-        let circlemax = 1
+        let circlemax = 1;
         this.props.min ? circlemin = this.props.min : null;
         this.props.max ? circlemax = this.props.max : null;
-        let avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2;
-        let degrees = 360 * avg;
-        let x = 125 * Math.cos(degrees * Math.PI / 180);
-        let y = -100 * Math.sin(degrees * Math.PI / 180);
+        const avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2;
+        const degrees = 360 * avg;
+        const x = 125 * Math.cos(degrees * Math.PI / 180);
+        const y = -100 * Math.sin(degrees * Math.PI / 180);
         return y;
     }
 
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 548066f1c..7c58a5148 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -142,7 +142,7 @@ export class ScreenshotBox extends DocAnnotatableComponent<FieldViewProps, Scree
     toggleRecording = action(async () => {
         this._screenCapture = !this._screenCapture;
         this._videoRef!.srcObject = !this._screenCapture ? undefined : await (navigator.mediaDevices as any).getDisplayMedia({ video: true });
-    })
+    });
 
     private get uIButtons() {
         return (<div className="screenshotBox-uiButtons">
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 591864f2c..838fbefb1 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -63,7 +63,7 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
                 this.layoutDoc._height = NumCast(this.layoutDoc._width) / youtubeaspect;
             }
         } else if (field?.url) {
-            var result = await WebRequest.get(Utils.CorsProxy(field.url.href));
+            const result = await WebRequest.get(Utils.CorsProxy(field.url.href));
             this.dataDoc.text = htmlToText.fromString(result.content);
         }
 
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index a1e7d5c2a..cc187cd67 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -238,7 +238,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
         this._pdfViewer.currentScaleValue = this._zoomed = 1;
         this.gotoPage(this.Document.curPage || 1);
         document.removeEventListener("pagesinit", this.pagesinit);
-    })
+    });
 
     createPdfViewer() {
         if (!this._mainCont.current) { // bcz: I don't think this is ever triggered or needed
diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx
index 9c339e986..1d52ba38f 100644
--- a/src/client/views/webcam/DashWebRTCVideo.tsx
+++ b/src/client/views/webcam/DashWebRTCVideo.tsx
@@ -36,7 +36,7 @@ export class DashWebRTCVideo extends React.Component<CollectionFreeFormDocumentV
       */
     private onEnterKeyDown = (e: React.KeyboardEvent) => {
         if (e.keyCode === 13) {
-            let submittedTitle = this.roomText!.value;
+            const submittedTitle = this.roomText!.value;
             this.roomText!.value = "";
             this.roomText!.blur();
             initialize(submittedTitle, this.changeUILook);
@@ -56,7 +56,7 @@ export class DashWebRTCVideo extends React.Component<CollectionFreeFormDocumentV
     }
 
     render() {
-        let content =
+        const content =
             <div className="webcam-cont" style={{ width: "100%", height: "100%" }}>
                 <div className="webcam-header">DashWebRTC</div>
                 <input id="roomName" type="text" placeholder="Enter room name" ref={(e) => this.roomText = e!} onKeyDown={this.onEnterKeyDown} />
@@ -72,8 +72,8 @@ export class DashWebRTCVideo extends React.Component<CollectionFreeFormDocumentV
                 </div>
             </div >;
 
-        let frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
-        let classname = "webBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !DocumentDecorations.Instance.Interacting ? "-interactive" : "");
+        const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
+        const classname = "webBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !DocumentDecorations.Instance.Interacting ? "-interactive" : "");
 
 
         return (
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 5d3a517ae..1d2d57b96 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -199,6 +199,8 @@ export default class MobileInterface extends React.Component {
                         DataDoc={undefined}
                         LibraryPath={emptyPath}
                         fieldKey={""}
+                        dropAction={"alias"}
+                        bringToFront={emptyFunction }
                         addDocTab={returnFalse}
                         pinToPres={emptyFunction}
                         PanelHeight={() => window.innerHeight}
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 25b526168..440f13d6b 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -353,7 +353,7 @@ export namespace Doc {
     // and returns the document who's proto is undefined or whose proto is marked as a base prototype ('isPrototype').
     export function GetProto(doc: Doc): Doc {
         if (doc instanceof Promise) {
-            console.log("GetProto: error: got Promise insead of Doc")
+            console.log("GetProto: error: got Promise insead of Doc");
         }
         const proto = doc && (Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : (doc.proto || doc));
         return proto === doc ? proto : Doc.GetProto(proto);
@@ -697,7 +697,7 @@ export namespace Doc {
     // the document containing the view layout information - will be the Document itself unless the Document has
     // a layout field or 'layout' is given.  
     export function Layout(doc: Doc, layout?: Doc): Doc {
-        const overrideLayout = layout && Cast(doc["data-layout[" + layout[Id] + "]"], Doc, null);
+        const overrideLayout = layout && Cast(doc[`${StrCast(layout.isTemplateForField, "data")}-layout[` + layout[Id] + "]"], Doc, null);
         return overrideLayout || doc[LayoutSym] || doc;
     }
     export function SetLayout(doc: Doc, layout: Doc | string) { doc[StrCast(doc.layoutKey, "layout")] = layout; }
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 3a1fd41f8..8c719ccd8 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -12,7 +12,7 @@ function _readOnlySetter(): never {
     throw new Error("Documents can't be modified in read-only mode");
 }
 
-let tracing = false;
+const tracing = false;
 export function TraceMobx() {
     tracing && trace();
 }
diff --git a/src/server/DashSession/Session/agents/applied_session_agent.ts b/src/server/DashSession/Session/agents/applied_session_agent.ts
index 46c9e22ed..12064668b 100644
--- a/src/server/DashSession/Session/agents/applied_session_agent.ts
+++ b/src/server/DashSession/Session/agents/applied_session_agent.ts
@@ -44,7 +44,7 @@ export abstract class AppliedSessionAgent {
         if (!this.launched) {
             this.launched = true;
             if (isMaster) {
-                this.sessionMonitorRef = Monitor.Create()
+                this.sessionMonitorRef = Monitor.Create();
                 const sessionKey = await this.initializeMonitor(this.sessionMonitorRef);
                 this.sessionMonitorRef.finalize(sessionKey);
             } else {
diff --git a/src/server/DashSession/Session/agents/monitor.ts b/src/server/DashSession/Session/agents/monitor.ts
index 6f8d25614..ee8afee65 100644
--- a/src/server/DashSession/Session/agents/monitor.ts
+++ b/src/server/DashSession/Session/agents/monitor.ts
@@ -167,7 +167,7 @@ export class Monitor extends IPCMessageReceiver {
      * and pass down any variables the pertinent to the child processes as environment variables.
      */
     private loadAndValidateConfiguration = (): Configuration => {
-        let config: Configuration;
+        let config: Configuration | undefined;
         try {
             console.log(this.timestamp(), cyan("validating configuration..."));
             config = JSON.parse(readFileSync('./session.config.json', 'utf8'));
diff --git a/src/server/DashSession/Session/agents/promisified_ipc_manager.ts b/src/server/DashSession/Session/agents/promisified_ipc_manager.ts
index 9f0db8330..feff568e1 100644
--- a/src/server/DashSession/Session/agents/promisified_ipc_manager.ts
+++ b/src/server/DashSession/Session/agents/promisified_ipc_manager.ts
@@ -35,8 +35,8 @@ export type MessageHandler<T = any> = (args: T) => (any | Promise<any>);
  * When a message is emitted, it is embedded with private metadata
  * to facilitate the resolution of promises, etc.
  */
-interface InternalMessage extends Message { metadata: Metadata }
-interface Metadata { isResponse: boolean; id: string }
+interface InternalMessage extends Message { metadata: Metadata; }
+interface Metadata { isResponse: boolean; id: string; }
 type InternalMessageHandler = (message: InternalMessage) => (any | Promise<any>);
 
 /**
@@ -133,7 +133,7 @@ export class PromisifiedIPCManager {
         Object.keys(pendingMessages).forEach(id => {
             const error: ErrorLike = { name: "ManagerDestroyed", message: "The IPC manager was destroyed before the response could be returned." };
             const message: InternalMessage = { name: pendingMessages[id], args: { error }, metadata: { id, isResponse: true } };
-            this.target.send?.(message)
+            this.target.send?.(message);
         });
         this.pendingMessages = {};
     }
diff --git a/src/server/Websocket/Websocket.ts b/src/server/Websocket/Websocket.ts
index c5dc22912..9f9fc9619 100644
--- a/src/server/Websocket/Websocket.ts
+++ b/src/server/Websocket/Websocket.ts
@@ -55,8 +55,8 @@ export namespace WebSocket {
             socket.on('create or join', function (room) {
                 console.log('Received request to create or join room ' + room);
 
-                var clientsInRoom = socket.adapter.rooms[room];
-                var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;
+                const clientsInRoom = socket.adapter.rooms[room];
+                const numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;
                 console.log('Room ' + room + ' now has ' + numClients + ' client(s)');
 
                 if (numClients === 0) {
@@ -76,8 +76,8 @@ export namespace WebSocket {
             });
 
             socket.on('ipaddr', function () {
-                var ifaces = networkInterfaces();
-                for (var dev in ifaces) {
+                const ifaces = networkInterfaces();
+                for (const dev in ifaces) {
                     ifaces[dev].forEach(function (details) {
                         if (details.family === 'IPv4' && details.address !== '127.0.0.1') {
                             socket.emit('ipaddr', details.address);
diff --git a/src/server/database.ts b/src/server/database.ts
index 055f04c49..fc91ff3a2 100644
--- a/src/server/database.ts
+++ b/src/server/database.ts
@@ -328,7 +328,7 @@ export namespace Database {
 
         export const LogUpload = async (information: Upload.ImageInformation) => {
             const bundle = {
-                _id: Utils.GenerateDeterministicGuid(String(information.contentSize!)),
+                _id: Utils.GenerateDeterministicGuid(String(information.contentSize)),
                 ...information
             };
             return Instance.insert(bundle, AuxiliaryCollections.GooglePhotosUploadHistory);
diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts
index 7b2228831..1150118f7 100644
--- a/src/server/server_Initialization.ts
+++ b/src/server/server_Initialization.ts
@@ -123,7 +123,7 @@ function registerCorsProxy(server: express.Express) {
     const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
     server.use("/corsProxy", (req, res) => {
 
-        let requrl = decodeURIComponent(req.url.substring(1));
+        const requrl = decodeURIComponent(req.url.substring(1));
         const referer = req.headers.referer ? decodeURIComponent(req.headers.referer) : "";
         // cors weirdness here... 
         // if the referer is a cors page and the cors() route (I think) redirected to /corsProxy/<path> and the requested url path was relative, 
-- 
cgit v1.2.3-70-g09d2


From adabfbea2b034beb310530aef9cc8b206e260b67 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 3 Apr 2020 20:23:15 -0400
Subject: added rootSelected() to make forceActive work better

---
 src/client/documents/Documents.ts                  |  2 +-
 src/client/util/RichTextSchema.tsx                 |  1 +
 src/client/views/DocComponent.tsx                  |  6 +++--
 src/client/views/GestureOverlay.tsx                |  1 +
 src/client/views/MainView.tsx                      |  4 ++++
 src/client/views/OverlayView.tsx                   |  1 +
 src/client/views/Palette.tsx                       | 26 +++++++---------------
 src/client/views/RecommendationsBox.tsx            |  1 +
 src/client/views/SearchDocBox.tsx                  |  3 ++-
 .../views/collections/CollectionDockingView.tsx    |  1 +
 .../views/collections/CollectionLinearView.tsx     |  3 ++-
 .../views/collections/CollectionSchemaView.tsx     |  1 +
 .../views/collections/CollectionStackingView.tsx   |  1 +
 src/client/views/collections/CollectionSubView.tsx |  5 +++++
 .../views/collections/CollectionTreeView.tsx       |  2 ++
 src/client/views/collections/CollectionView.tsx    |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  1 +
 .../collections/collectionFreeForm/MarqueeView.tsx |  1 -
 src/client/views/nodes/AudioBox.tsx                | 12 +++++++---
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  7 +++---
 .../views/nodes/ContentFittingDocumentView.tsx     |  1 +
 src/client/views/nodes/DocumentBox.tsx             |  1 +
 src/client/views/nodes/DocumentContentsView.tsx    |  4 ++--
 src/client/views/nodes/DocumentView.tsx            | 24 +++++++++++++++-----
 src/client/views/nodes/FieldView.tsx               |  1 +
 src/client/views/nodes/FormattedTextBoxComment.tsx |  1 +
 src/client/views/pdf/PDFViewer.tsx                 |  3 +--
 .../views/presentationview/PresElementBox.tsx      |  3 ++-
 src/client/views/search/SearchItem.tsx             |  3 ++-
 src/mobile/MobileInterface.tsx                     |  2 ++
 .../authentication/models/current_user_utils.ts    |  2 +-
 31 files changed, 83 insertions(+), 43 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index a69bfae01..0a2269bac 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -435,7 +435,7 @@ export namespace Docs {
         Scripting.addGlobal(Buxton);
 
         const delegateKeys = ["x", "y", "layoutKey", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "dropAction", "childDropAction", "_annotationOn",
-            "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "_showTitle", "_showCaption", "_showTitleHover", "_backgroundColor",
+            "_chromeStatus", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "_showTitle", "_showCaption", "_showTitleHover", "_backgroundColor",
             "_xMargin", "_yMargin", "_xPadding", "_yPadding", "_singleLine", "_scrollTop",
             "_color", "isButton", "isBackground", "removeDropProperties", "treeViewOpen"];
 
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 094cd58f3..4a930177d 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -818,6 +818,7 @@ export class DashDocView {
                     LibraryPath={this._textBox.props.LibraryPath}
                     fitToBox={BoolCast(dashDoc._fitToBox)}
                     addDocument={returnFalse}
+                    rootSelected={this._textBox.props.isSelected}
                     removeDocument={removeDoc}
                     ScreenToLocalTransform={this.getDocTransform}
                     addDocTab={this._textBox.props.addDocTab}
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index f4e830a48..454c245cc 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -29,6 +29,7 @@ interface DocExtendableProps {
     fieldKey: string;
     isSelected: (outsideReaction?: boolean) => boolean;
     renderDepth: number;
+    rootSelected: () => boolean;
 }
 export function DocExtendableComponent<P extends DocExtendableProps, T>(schemaCtor: (doc: Doc) => T) {
     class Component extends Touchable<P> {
@@ -36,7 +37,7 @@ export function DocExtendableComponent<P extends DocExtendableProps, T>(schemaCt
         @computed get Document(): T { return schemaCtor(this.props.Document); }
         @computed get layoutDoc() { return Doc.Layout(this.props.Document); }
         @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Cast(this.props.Document.resolvedDataDoc, Doc, null) || Doc.GetProto(this.props.Document)) as Doc; }
-        active = (outsideReaction?: boolean) => !this.props.Document.isBackground && (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);//  && !InkingControl.Instance.selectedTool;  // bcz: inking state shouldn't affect static tools 
+        active = (outsideReaction?: boolean) => !this.props.Document.isBackground && ((this.props.Document.forceActive && this.props.rootSelected()) || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);//  && !InkingControl.Instance.selectedTool;  // bcz: inking state shouldn't affect static tools 
     }
     return Component;
 }
@@ -50,6 +51,7 @@ export interface DocAnnotatableProps {
     active: () => boolean;
     whenActiveChanged: (isActive: boolean) => void;
     isSelected: (outsideReaction?: boolean) => boolean;
+    rootSelected: () => boolean;
     renderDepth: number;
 }
 export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schemaCtor: (doc: Doc) => T) {
@@ -86,7 +88,7 @@ export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schema
 
         whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive));
         active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.props.Document.isBackground) &&
-            (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
+            ((this.props.Document.forceActive && this.props.rootSelected()) || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
         annotationsActive = (outsideReaction?: boolean) => (InkingControl.Instance.selectedTool !== InkTool.None ||
             (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
     }
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index ea60907f6..26bee9a6f 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -705,6 +705,7 @@ export default class GestureOverlay extends Touchable {
                 LibraryPath={emptyPath}
                 addDocument={undefined}
                 addDocTab={returnFalse}
+                rootSelected={returnTrue}
                 pinToPres={emptyFunction}
                 onClick={undefined}
                 removeDocument={undefined}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 8d9be5980..fae520e40 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -309,6 +309,7 @@ export class MainView extends React.Component {
             addDocument={undefined}
             addDocTab={this.addDocTabFunc}
             pinToPres={emptyFunction}
+            rootSelected={returnTrue}
             onClick={undefined}
             backgroundColor={this.defaultBackgroundColors}
             removeDocument={undefined}
@@ -407,6 +408,7 @@ export class MainView extends React.Component {
                     DataDoc={undefined}
                     LibraryPath={emptyPath}
                     addDocument={undefined}
+                    rootSelected={returnTrue}
                     addDocTab={this.addDocTabFunc}
                     pinToPres={emptyFunction}
                     removeDocument={undefined}
@@ -435,6 +437,7 @@ export class MainView extends React.Component {
                     addDocument={undefined}
                     addDocTab={this.addDocTabFunc}
                     pinToPres={emptyFunction}
+                    rootSelected={returnTrue}
                     removeDocument={returnFalse}
                     onClick={undefined}
                     ScreenToLocalTransform={this.mainContainerXf}
@@ -523,6 +526,7 @@ export class MainView extends React.Component {
                     fieldKey={"data"}
                     dropAction={"alias"}
                     annotationsKey={""}
+                    rootSelected={returnTrue}
                     bringToFront={emptyFunction}
                     select={emptyFunction}
                     active={returnFalse}
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 220efd4a8..7587071db 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -174,6 +174,7 @@ export class OverlayView extends React.Component {
                     Document={d}
                     LibraryPath={emptyPath}
                     ChromeHeight={returnZero}
+                    rootSelected={returnTrue}
                     // isSelected={returnFalse}
                     // select={emptyFunction}
                     // layoutKey={"layout"}
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index e04f814d1..674b27918 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -1,23 +1,12 @@
+import { IReactionDisposer, observable, reaction } from "mobx";
+import { observer } from "mobx-react";
 import * as React from "react";
-import "./Palette.scss";
-import { PointData } from "../../new_fields/InkField";
 import { Doc } from "../../new_fields/Doc";
-import { Docs } from "../documents/Documents";
-import { ScriptField, ComputedField } from "../../new_fields/ScriptField";
-import { List } from "../../new_fields/List";
-import { DocumentView } from "./nodes/DocumentView";
-import { emptyPath, returnFalse, emptyFunction, returnOne, returnEmptyString, returnTrue } from "../../Utils";
-import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
+import { NumCast } from "../../new_fields/Types";
+import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue } from "../../Utils";
 import { Transform } from "../util/Transform";
-import { computed, action, IReactionDisposer, reaction, observable } from "mobx";
-import { FieldValue, Cast, NumCast } from "../../new_fields/Types";
-import { observer } from "mobx-react";
-import { DocumentContentsView } from "./nodes/DocumentContentsView";
-import { CollectionStackingView } from "./collections/CollectionStackingView";
-import { CollectionView } from "./collections/CollectionView";
-import { CollectionSubView, SubCollectionViewProps } from "./collections/CollectionSubView";
-import { makeInterface } from "../../new_fields/Schema";
-import { documentSchema } from "../../new_fields/documentSchemas";
+import { DocumentView } from "./nodes/DocumentView";
+import "./Palette.scss";
 
 export interface PaletteProps {
     x: number;
@@ -40,7 +29,7 @@ export default class Palette extends React.Component<PaletteProps> {
     }
 
     componentWillUnmount = () => {
-        this._selectedDisposer && this._selectedDisposer();
+        this._selectedDisposer?.();
     }
 
     render() {
@@ -54,6 +43,7 @@ export default class Palette extends React.Component<PaletteProps> {
                             LibraryPath={emptyPath}
                             addDocument={undefined}
                             addDocTab={returnFalse}
+                            rootSelected={returnTrue}
                             pinToPres={emptyFunction}
                             removeDocument={undefined}
                             onClick={undefined}
diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
index 5ebba0abb..bf8de36b4 100644
--- a/src/client/views/RecommendationsBox.tsx
+++ b/src/client/views/RecommendationsBox.tsx
@@ -68,6 +68,7 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
                 addDocument={returnFalse}
                 LibraryPath={emptyPath}
                 removeDocument={returnFalse}
+                rootSelected={returnFalse}
                 ScreenToLocalTransform={Transform.Identity}
                 addDocTab={returnFalse}
                 pinToPres={returnFalse}
diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
index c57f9e737..e66de39d4 100644
--- a/src/client/views/SearchDocBox.tsx
+++ b/src/client/views/SearchDocBox.tsx
@@ -410,8 +410,9 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
             <div style={{ pointerEvents: "all" }}>
                 <ContentFittingDocumentView {...this.props}
                     Document={this.content}
+                    rootSelected={returnFalse}
                     getTransform={this.props.ScreenToLocalTransform}>
-                    </ContentFittingDocumentView>
+                </ContentFittingDocumentView>
                 <div
                     style={{
                         position: "absolute",
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 4e1e76f39..4209bd574 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -788,6 +788,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             Document={document}
             DataDoc={resolvedDataDoc}
             bringToFront={emptyFunction}
+            rootSelected={returnTrue}
             addDocument={undefined}
             removeDocument={undefined}
             ContentScaling={this.contentScaling}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 344605412..a6ada75b2 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -4,7 +4,7 @@ import * as React from 'react';
 import { Doc, HeightSym, WidthSym } from '../../../new_fields/Doc';
 import { makeInterface } from '../../../new_fields/Schema';
 import { BoolCast, NumCast, StrCast, Cast } from '../../../new_fields/Types';
-import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils } from '../../../Utils';
+import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils, returnFalse } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { Transform } from '../../util/Transform';
 import "./CollectionLinearView.scss";
@@ -110,6 +110,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                                 moveDocument={this.props.moveDocument}
                                 addDocTab={this.props.addDocTab}
                                 pinToPres={emptyFunction}
+                                rootSelected={this.props.isSelected}
                                 removeDocument={this.props.removeDocument}
                                 onClick={undefined}
                                 ScreenToLocalTransform={this.getTransform(dref)}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 981438513..a1b541f74 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -124,6 +124,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
                 LibraryPath={this.props.LibraryPath}
                 childDocs={this.childDocs}
                 renderDepth={this.props.renderDepth}
+                rootSelected={this.rootSelected}
                 PanelWidth={this.previewWidth}
                 PanelHeight={this.previewHeight}
                 getTransform={this.getPreviewTransform}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 076dd3629..d21e17bbc 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -176,6 +176,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             LibraryPath={this.props.LibraryPath}
             renderDepth={this.props.renderDepth + 1}
             fitToBox={this.props.fitToBox}
+            rootSelected={this.rootSelected}
             dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             onClick={layoutDoc.isTemplateDoc ? this.onClickHandler : this.onChildClickHandler}
             PanelWidth={width}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 70927cf22..d1d6ae3c1 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -34,6 +34,7 @@ export interface CollectionViewProps extends FieldViewProps {
     PanelHeight: () => number;
     VisibleHeight?: () => number;
     setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
+    rootSelected: () => boolean;
     fieldKey: string;
 }
 
@@ -95,6 +96,10 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                 this.props.Document.resolvedDataDoc ? this.props.Document : Doc.GetProto(this.props.Document)); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template
         }
 
+        rootSelected = () => {
+            return this.props.isSelected() || (this.props.Document.rootDocument || this.props.Document.forceActive ? this.props.rootSelected() : false);
+        }
+
         // The data field for rendering this collection will be on the this.props.Document unless we're rendering a template in which case we try to use props.DataDoc.
         // When a document has a DataDoc but it's not a template, then it contains its own rendering data, but needs to pass the DataDoc through
         // to its children which may be templates.
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 6ee48f11b..fc612c66d 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -373,6 +373,7 @@ class TreeView extends React.Component<TreeViewProps> {
                     DataDocument={this.templateDataDoc}
                     LibraryPath={emptyPath}
                     renderDepth={this.props.renderDepth + 1}
+                    rootSelected={returnTrue}
                     backgroundColor={this.props.backgroundColor}
                     fitToBox={this.boundsOfCollectionDocument !== undefined}
                     PanelWidth={this.docWidth}
@@ -454,6 +455,7 @@ class TreeView extends React.Component<TreeViewProps> {
                         LibraryPath={this.props.libraryPath || []}
                         addDocument={undefined}
                         addDocTab={this.props.addDocTab}
+                        rootSelected={returnTrue}
                         pinToPres={emptyFunction}
                         onClick={this.props.onChildClick || editTitle}
                         dropAction={this.props.dropAction}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index df1770ffe..3913ccd88 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -117,7 +117,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
         return viewField;
     }
 
-    active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || BoolCast(this.props.Document.forceActive) || this._isChildActive || this.props.renderDepth === 0;
+    active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || (this.props.rootSelected() && BoolCast(this.props.Document.forceActive)) || this._isChildActive || this.props.renderDepth === 0;
 
     whenActiveChanged = (isActive: boolean) => { this.props.whenActiveChanged(this._isChildActive = isActive); };
 
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 2871fe192..a164e1794 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -832,6 +832,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             Document: childLayout,
             LibraryPath: this.libraryPath,
             layoutKey: undefined,
+            rootSelected: this.rootSelected,
             dropAction: StrCast(this.props.Document.childDropAction) as dropActionType,
             //onClick: undefined, // this.props.onClick,  // bcz: check this out -- I don't think we want to inherit click handlers, or we at least need a way to ignore them
             onClick: this.onChildClickHandler,
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 276a49570..503df10c2 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -5,7 +5,6 @@ import { InkField, InkData } from "../../../../new_fields/InkField";
 import { List } from "../../../../new_fields/List";
 import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField";
 import { Cast, NumCast, FieldValue, StrCast } from "../../../../new_fields/Types";
-import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils";
 import { Utils } from "../../../../Utils";
 import { Docs, DocUtils } from "../../../documents/Documents";
 import { SelectionManager } from "../../../util/SelectionManager";
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 03b2a2297..bd54d64ff 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -7,7 +7,7 @@ import { AudioField, nullAudio } from "../../../new_fields/URLField";
 import { DocExtendableComponent } from "../DocComponent";
 import { makeInterface, createSchema } from "../../../new_fields/Schema";
 import { documentSchema } from "../../../new_fields/documentSchemas";
-import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent } from "../../../Utils";
+import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse } from "../../../Utils";
 import { runInAction, observable, reaction, IReactionDisposer, computed, action } from "mobx";
 import { DateField } from "../../../new_fields/DateField";
 import { SelectionManager } from "../../util/SelectionManager";
@@ -258,9 +258,15 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
                                 return !linkTime ? (null) :
                                     <div className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container"} key={l[Id]} style={{ left: `${linkTime / NumCast(this.dataDoc.duration, 1) * 100}%` }}>
                                         <div className={this.props.PanelHeight() < 32 ? "audioBox-linker-mini" : "audioBox-linker"} key={"linker" + i}>
-                                            <DocumentView {...this.props} Document={l} layoutKey={Doc.LinkEndpoint(l, la2)}
+                                            <DocumentView {...this.props}
+                                                Document={l}
+                                                rootSelected={returnFalse}
+                                                layoutKey={Doc.LinkEndpoint(l, la2)}
                                                 ContainingCollectionDoc={this.props.Document}
-                                                parentActive={returnTrue} bringToFront={emptyFunction} zoomToScale={emptyFunction} getScale={returnOne}
+                                                parentActive={returnTrue}
+                                                bringToFront={emptyFunction}
+                                                zoomToScale={emptyFunction}
+                                                getScale={returnOne}
                                                 backgroundColor={returnTransparent} />
                                         </div>
                                         <div key={i} className="audiobox-marker" onPointerEnter={() => Doc.linkFollowHighlight(la1)}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index eaab4086c..356192797 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -89,14 +89,15 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 pointerEvents: this.props.Document.isBackground ? "none" : undefined
             }} >
 
-            {!this.props.fitToBox ? <DocumentView {...this.props}
+            {!this.props.fitToBox ? 
+            <DocumentView {...this.props}
                 dragDivName={"collectionFreeFormDocumentView-container"}
                 ContentScaling={this.contentScaling}
                 ScreenToLocalTransform={this.getTransform}
                 backgroundColor={this.props.backgroundColor}
                 PanelWidth={this.panelWidth}
-                PanelHeight={this.panelHeight}
-            /> : <ContentFittingDocumentView {...this.props}
+                PanelHeight={this.panelHeight} /> 
+            : <ContentFittingDocumentView {...this.props}
                 CollectionDoc={this.props.ContainingCollectionDoc}
                 DataDocument={this.props.DataDoc}
                 getTransform={this.getTransform}
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 9494a4bc4..fdf2a9551 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -40,6 +40,7 @@ interface ContentFittingDocumentViewProps {
     addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     dontRegisterView?: boolean;
+    rootSelected: () => boolean;
 }
 
 @observer
diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx
index debe104d7..47118e758 100644
--- a/src/client/views/nodes/DocumentBox.tsx
+++ b/src/client/views/nodes/DocumentBox.tsx
@@ -122,6 +122,7 @@ export class DocumentBox extends DocAnnotatableComponent<FieldViewProps, DocBoxS
             CollectionView={this as any} // bcz: hack!  need to pass a prop that can be used to select the container (ie, 'this') when the up selector in document decorations is clicked.  currently, the up selector allows only a containing collection to be selected
             fitToBox={this.props.fitToBox}
             layoutKey={"layout_" + childTemplateName}
+            rootSelected={this.props.isSelected}
             addDocument={this.props.addDocument}
             moveDocument={this.props.moveDocument}
             removeDocument={this.props.removeDocument}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index fc61487e5..687137adc 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -1,6 +1,6 @@
 import { computed } from "mobx";
 import { observer } from "mobx-react";
-import { Doc } from "../../../new_fields/Doc";
+import { Doc, Opt } from "../../../new_fields/Doc";
 import { Cast, StrCast } from "../../../new_fields/Types";
 import { OmitKeys, Without } from "../../../Utils";
 import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox";
@@ -62,7 +62,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
     forceLayout?: string,
     forceFieldKey?: string,
     hideOnLeave?: boolean,
-    makeLink?: () => Opt<Doc>;
+    makeLink?: () => Opt<Doc>,  // function to call when a link is made
 }> {
     @computed get layout(): string {
         TraceMobx();
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 1e02ab44e..42f5fb946 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -60,6 +60,7 @@ export interface DocumentViewProps {
     LayoutDoc?: () => Opt<Doc>;
     LibraryPath: Doc[];
     fitToBox?: boolean;
+    rootSelected: () => boolean; // whether the root of a template has been selected
     onClick?: ScriptField;
     onPointerDown?: ScriptField;
     onPointerUp?: ScriptField;
@@ -277,7 +278,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         this.dontDecorateSelection = this.props.Document.dontDecorateSelection && (!e.ctrlKey || e.button < 2);
         if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick &&
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
-            e.stopPropagation();
+            let stopPropagate = true;
             let preventDefault = true;
             this.props.bringToFront(this.props.Document);
             if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
@@ -301,9 +302,14 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 SelectionManager.SelectDoc(this, e.ctrlKey); // don't think this should happen if a button action is actually triggered.
                 UndoManager.RunInBatch(() => this.buttonClick(e.altKey, e.ctrlKey), "on link button follow");
             } else {
-                SelectionManager.SelectDoc(this, e.ctrlKey);
+                if (this.props.Document.isTemplateForField && !(e.ctrlKey || e.button > 0)) {
+                    stopPropagate = false;
+                } else {
+                    SelectionManager.SelectDoc(this, e.ctrlKey);
+                }
                 preventDefault = false;
             }
+            stopPropagate && e.stopPropagation();
             preventDefault && e.preventDefault();
         }
     }
@@ -928,6 +934,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const fallback = Cast(this.props.Document.layoutKey, "string");
         return typeof fallback === "string" ? fallback : "layout";
     }
+    rootSelected = () => {
+        return this.isSelected(false) || (this.props.Document.forceActive && this.props.rootSelected?.() ? true : false);
+    }
     childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
     @computed get contents() {
         TraceMobx();
@@ -937,6 +946,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             DataDoc={this.props.DataDoc}
             LayoutDoc={this.props.LayoutDoc}
             makeLink={this.makeLink}
+            rootSelected={this.rootSelected}
             fitToBox={this.props.fitToBox}
             LibraryPath={this.props.LibraryPath}
             addDocument={this.props.addDocument}
@@ -985,9 +995,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 {StrCast(this.props.Document.title)}
                 {this.Document.links && DocListCast(this.Document.links).filter(d => !d.hidden).filter(this.isNonTemporalLink).map((d, i) =>
                     <div className="documentView-docuLinkWrapper" style={{ position: "absolute", top: 0, left: 0 }} key={`${d[Id]}`}>
-                        <DocumentView {...this.props} Document={d} ContainingCollectionDoc={this.props.Document}
-                            PanelWidth={returnOne} PanelHeight={returnOne} layoutKey={this.linkEndpoint(d)} ContentScaling={returnOne}
-                            backgroundColor={returnTransparent} removeDocument={undoBatch(doc => doc.hidden = true)} />
+                        <DocumentView {...this.props}
+                            Document={d}
+                            ContainingCollectionDoc={this.props.Document}
+                            PanelWidth={returnOne} PanelHeight={returnOne}
+                            layoutKey={this.linkEndpoint(d)} ContentScaling={returnOne}
+                            backgroundColor={returnTransparent}
+                            removeDocument={undoBatch(doc => doc.hidden = true)} />
                     </div>)}
             </div>;
         }
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 0305f43d5..13a1becf7 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -29,6 +29,7 @@ export interface FieldViewProps {
     dropAction: dropActionType;
     isSelected: (outsideReaction?: boolean) => boolean;
     select: (isCtrlPressed: boolean) => void;
+    rootSelected: () => boolean;
     renderDepth: number;
     addDocument?: (document: Doc) => boolean;
     addDocTab: (document: Doc, where: string) => boolean;
diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx
index 61df188f8..d1a563494 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/FormattedTextBoxComment.tsx
@@ -181,6 +181,7 @@ export class FormattedTextBoxComment {
                                     LibraryPath={emptyPath}
                                     fitToBox={true}
                                     moveDocument={returnFalse}
+                                    rootSelected={returnFalse}
                                     getTransform={Transform.Identity}
                                     active={returnFalse}
                                     addDocument={returnFalse}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 71495d95f..c032f019d 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -31,8 +31,6 @@ import { InkingControl } from "../InkingControl";
 import { InkTool } from "../../../new_fields/InkField";
 import { TraceMobx } from "../../../new_fields/util";
 import { PdfField } from "../../../new_fields/URLField";
-import { PDFBox } from "../nodes/PDFBox";
-import { FormattedTextBox } from "../nodes/FormattedTextBox";
 import { DocumentView } from "../nodes/DocumentView";
 const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer");
 const pdfjsLib = require("pdfjs-dist");
@@ -61,6 +59,7 @@ interface IViewerProps {
     PanelHeight: () => number;
     ContentScaling: () => number;
     select: (isCtrlPressed: boolean) => void;
+    rootSelected: () => boolean;
     startupLive: boolean;
     renderDepth: number;
     focus: (doc: Doc) => void;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 758795ed5..7ad3474e8 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -9,7 +9,7 @@ import { documentSchema } from '../../../new_fields/documentSchemas';
 import { Id } from "../../../new_fields/FieldSymbols";
 import { createSchema, makeInterface } from '../../../new_fields/Schema';
 import { Cast, NumCast } from "../../../new_fields/Types";
-import { emptyFunction, emptyPath, returnFalse } from "../../../Utils";
+import { emptyFunction, emptyPath, returnFalse, returnTrue } from "../../../Utils";
 import { Transform } from "../../util/Transform";
 import { CollectionViewType } from '../collections/CollectionView';
 import { DocExtendableComponent } from '../DocComponent';
@@ -175,6 +175,7 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
                     DataDocument={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
                     LibraryPath={emptyPath}
                     fitToBox={true}
+                    rootSelected={returnTrue}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
                     addDocTab={returnFalse}
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 63cef5101..0d77026ad 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -7,7 +7,7 @@ import { observer } from "mobx-react";
 import { Doc } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { emptyFunction, emptyPath, returnFalse, Utils } from "../../../Utils";
+import { emptyFunction, emptyPath, returnFalse, Utils, returnTrue } from "../../../Utils";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { DocumentManager } from "../../util/DocumentManager";
 import { DragManager, SetupDrag } from "../../util/DragManager";
@@ -158,6 +158,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
                 <ContentFittingDocumentView
                     Document={this.props.doc}
                     LibraryPath={emptyPath}
+                    rootSelected={returnFalse}
                     fitToBox={StrCast(this.props.doc.type).indexOf(DocumentType.COL) !== -1}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 1d2d57b96..98a6d384e 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -124,6 +124,7 @@ export default class MobileInterface extends React.Component {
                 addDocument={returnFalse}
                 addDocTab={returnFalse}
                 pinToPres={emptyFunction}
+                rootSelected={returnFalse}
                 removeDocument={undefined}
                 onClick={undefined}
                 ScreenToLocalTransform={Transform.Identity}
@@ -285,6 +286,7 @@ export default class MobileInterface extends React.Component {
                         addDocument={returnFalse}
                         addDocTab={returnFalse}
                         pinToPres={emptyFunction}
+                        rootSelected={returnFalse}
                         removeDocument={undefined}
                         onClick={undefined}
                         ScreenToLocalTransform={Transform.Identity}
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 9a90ce17f..7fe623f18 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -213,7 +213,7 @@ export class CurrentUserUtils {
             _width: 35, _height: 25, title: "Tools", fontSize: 10, targetContainer: sidebarContainer, dontDecorateSelection: true,
             letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
             sourcePanel: Docs.Create.StackingDocument([dragCreators, color], {
-                _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack"
+                _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true
             }),
             onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"),
         });
-- 
cgit v1.2.3-70-g09d2


From 48478855cc28aa423b2d1e482bd181c8c5066da6 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 5 Apr 2020 15:13:25 -0400
Subject: adding nativeWidth as props stuff

---
 src/client/util/RichTextSchema.tsx                 |  4 +-
 src/client/views/GestureOverlay.tsx                | 13 ++++---
 src/client/views/MainView.tsx                      | 10 ++++-
 src/client/views/OverlayView.tsx                   |  2 +
 src/client/views/Palette.tsx                       |  4 +-
 src/client/views/RecommendationsBox.tsx            |  4 +-
 src/client/views/TemplateMenu.tsx                  |  6 ++-
 .../views/collections/CollectionDockingView.tsx    |  4 +-
 .../views/collections/CollectionLinearView.tsx     |  6 ++-
 .../views/collections/CollectionSchemaCells.tsx    |  2 +
 .../views/collections/CollectionStackingView.tsx   | 32 +++++++++------
 src/client/views/collections/CollectionSubView.tsx |  8 ++--
 .../views/collections/CollectionTimeView.tsx       |  5 +--
 .../views/collections/CollectionTreeView.tsx       |  2 +
 src/client/views/collections/CollectionView.tsx    |  4 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  5 ++-
 src/client/views/nodes/AudioBox.tsx                |  4 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx | 45 +++++++++++++---------
 .../views/nodes/ContentFittingDocumentView.tsx     | 25 +++++++-----
 src/client/views/nodes/DocumentView.tsx            | 14 +++++--
 src/client/views/nodes/FieldView.tsx               |  2 +
 src/client/views/nodes/FormattedTextBox.tsx        |  4 +-
 src/client/views/nodes/ImageBox.tsx                |  4 +-
 src/client/views/nodes/KeyValuePair.tsx            |  6 ++-
 src/client/views/nodes/LinkBox.tsx                 |  2 +
 src/client/views/nodes/ScreenshotBox.tsx           |  4 +-
 src/client/views/nodes/VideoBox.tsx                |  4 +-
 src/client/views/nodes/WebBox.tsx                  |  4 +-
 src/client/views/pdf/PDFViewer.tsx                 |  4 +-
 src/mobile/MobileInterface.tsx                     | 14 +++++--
 src/new_fields/documentSchemas.ts                  |  2 +-
 src/new_fields/util.ts                             |  2 +-
 32 files changed, 170 insertions(+), 81 deletions(-)

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

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index d4568b17f..de2707d36 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -16,7 +16,7 @@ import { listSpec } from "../../new_fields/Schema";
 import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField";
 import { ComputedField } from "../../new_fields/ScriptField";
 import { BoolCast, Cast, NumCast, StrCast } from "../../new_fields/Types";
-import { emptyFunction, returnEmptyString, returnFalse, returnOne, Utils } from "../../Utils";
+import { emptyFunction, returnEmptyString, returnFalse, returnOne, Utils, returnZero } from "../../Utils";
 import { DocServer } from "../DocServer";
 import { Docs } from "../documents/Documents";
 import { CollectionViewType } from "../views/collections/CollectionView";
@@ -824,6 +824,8 @@ export class DashDocView {
                     addDocTab={this._textBox.props.addDocTab}
                     pinToPres={returnFalse}
                     renderDepth={self._textBox.props.renderDepth + 1}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
                     PanelWidth={finalLayout[WidthSym]}
                     PanelHeight={finalLayout[HeightSym]}
                     focus={this.outerFocus}
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 68f1d13fb..110b61efe 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -15,7 +15,7 @@ import { Scripting } from "../util/Scripting";
 import { FieldValue, Cast, NumCast, BoolCast } from "../../new_fields/Types";
 import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
 import HorizontalPalette from "./Palette";
-import { Utils, emptyPath, emptyFunction, returnFalse, returnOne, returnEmptyString, returnTrue, numberRange } from "../../Utils";
+import { Utils, emptyPath, emptyFunction, returnFalse, returnOne, returnEmptyString, returnTrue, numberRange, returnZero } from "../../Utils";
 import { DocumentView } from "./nodes/DocumentView";
 import { Transform } from "../util/Transform";
 import { DocumentContentsView } from "./nodes/DocumentContentsView";
@@ -695,7 +695,8 @@ export default class GestureOverlay extends Touchable {
             </svg>]
         ];
     }
-
+    screenToLocalTransform = () => new Transform(-(this._thumbX ?? 0), -(this._thumbY ?? 0) + this.height, 1);
+    return300 = () => 300;
     @action
     public openFloatingDoc = (doc: Doc) => {
         this._clipboardDoc =
@@ -709,10 +710,12 @@ export default class GestureOverlay extends Touchable {
                 pinToPres={emptyFunction}
                 onClick={undefined}
                 removeDocument={undefined}
-                ScreenToLocalTransform={() => new Transform(-(this._thumbX ?? 0), -(this._thumbY ?? 0) + this.height, 1)}
+                ScreenToLocalTransform={this.screenToLocalTransform}
                 ContentScaling={returnOne}
-                PanelWidth={() => 300}
-                PanelHeight={() => 300}
+                PanelWidth={this.return300}
+                PanelHeight={this.return300}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
                 renderDepth={0}
                 backgroundColor={returnEmptyString}
                 focus={emptyFunction}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 420cc95ec..bef92f0fd 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -13,7 +13,7 @@ import { listSpec } from '../../new_fields/Schema';
 import { BoolCast, Cast, FieldValue, StrCast } from '../../new_fields/Types';
 import { TraceMobx } from '../../new_fields/util';
 import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
-import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, Utils } from '../../Utils';
+import { emptyFunction, emptyPath, returnFalse, returnOne, returnZero, returnTrue, Utils } from '../../Utils';
 import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
 import { DocServer } from '../DocServer';
 import { Docs, DocumentOptions } from '../documents/Documents';
@@ -307,6 +307,8 @@ export class MainView extends React.Component {
             removeDocument={undefined}
             ScreenToLocalTransform={Transform.Identity}
             ContentScaling={returnOne}
+            NativeHeight={returnZero}
+            NativeWidth={returnZero}
             PanelWidth={this.getPWidth}
             PanelHeight={this.getPHeight}
             renderDepth={0}
@@ -405,6 +407,8 @@ export class MainView extends React.Component {
                     onClick={undefined}
                     ScreenToLocalTransform={Transform.Identity}
                     ContentScaling={returnOne}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
                     PanelWidth={this.flyoutWidthFunc}
                     PanelHeight={this.getPHeight}
                     renderDepth={0}
@@ -424,6 +428,8 @@ export class MainView extends React.Component {
                     addDocument={undefined}
                     addDocTab={this.addDocTabFunc}
                     pinToPres={emptyFunction}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
                     rootSelected={returnTrue}
                     removeDocument={returnFalse}
                     onClick={undefined}
@@ -524,6 +530,8 @@ export class MainView extends React.Component {
                     onClick={undefined}
                     ScreenToLocalTransform={this.buttonBarXf}
                     ContentScaling={returnOne}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
                     PanelWidth={this.flyoutWidthFunc}
                     PanelHeight={this.getContentsHeight}
                     renderDepth={0}
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 7cfae0bbb..4000cade5 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -182,6 +182,8 @@ export class OverlayView extends React.Component {
                     addDocument={undefined}
                     removeDocument={undefined}
                     ContentScaling={returnOne}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
                     PanelWidth={returnOne}
                     PanelHeight={returnOne}
                     ScreenToLocalTransform={Transform.Identity}
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index d088d5bba..63744cb50 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -3,7 +3,7 @@ import { observer } from "mobx-react";
 import * as React from "react";
 import { Doc } from "../../new_fields/Doc";
 import { NumCast } from "../../new_fields/Types";
-import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue } from "../../Utils";
+import { emptyFunction, emptyPath, returnEmptyString, returnZero, returnFalse, returnOne, returnTrue } from "../../Utils";
 import { Transform } from "../util/Transform";
 import { DocumentView } from "./nodes/DocumentView";
 import "./Palette.scss";
@@ -49,6 +49,8 @@ export default class Palette extends React.Component<PaletteProps> {
                             onClick={undefined}
                             ScreenToLocalTransform={Transform.Identity}
                             ContentScaling={returnOne}
+                            NativeHeight={returnZero}
+                            NativeWidth={returnZero}
                             PanelWidth={() => window.screen.width}
                             PanelHeight={() => window.screen.height}
                             renderDepth={0}
diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
index ddeda28ac..e66fd3eb4 100644
--- a/src/client/views/RecommendationsBox.tsx
+++ b/src/client/views/RecommendationsBox.tsx
@@ -6,7 +6,7 @@ import "./RecommendationsBox.scss";
 import { Doc, DocListCast, WidthSym, HeightSym } from "../../new_fields/Doc";
 import { DocumentIcon } from "./nodes/DocumentIcon";
 import { StrCast, NumCast } from "../../new_fields/Types";
-import { returnFalse, emptyFunction, returnEmptyString, returnOne, emptyPath } from "../../Utils";
+import { returnFalse, emptyFunction, returnEmptyString, returnOne, emptyPath, returnZero } from "../../Utils";
 import { Transform } from "../util/Transform";
 import { ObjectField } from "../../new_fields/ObjectField";
 import { DocumentView } from "./nodes/DocumentView";
@@ -73,6 +73,8 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
                 addDocTab={returnFalse}
                 pinToPres={returnFalse}
                 renderDepth={1}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
                 PanelWidth={returnXDimension}
                 PanelHeight={returnYDimension}
                 focus={emptyFunction}
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index f2fb26679..c72f3681a 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -10,7 +10,7 @@ import { Doc, DocListCast } from "../../new_fields/Doc";
 import { Docs, } from "../documents/Documents";
 import { StrCast, Cast } from "../../new_fields/Types";
 import { CollectionTreeView } from "./collections/CollectionTreeView";
-import { returnTrue, emptyFunction, returnFalse, returnOne, emptyPath } from "../../Utils";
+import { returnTrue, emptyFunction, returnFalse, returnOne, emptyPath, returnZero } from "../../Utils";
 import { Transform } from "../util/Transform";
 import { ScriptField, ComputedField } from "../../new_fields/ScriptField";
 import { Scripting } from "../util/Scripting";
@@ -149,6 +149,8 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                     select={emptyFunction}
                     renderDepth={1}
                     addDocTab={returnFalse}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
                     PanelWidth={this.return100}
                     PanelHeight={this.return100}
                     treeViewHideHeaderFields={true}
@@ -161,7 +163,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
             );
         }
         return <ul className="template-list" style={{ display: "block" }}>
-            <input placeholder="+ layout" ref={this._customRef} onKeyPress={this.onCustomKeypress}/>
+            <input placeholder="+ layout" ref={this._customRef} onKeyPress={this.onCustomKeypress} />
             {templateMenu}
         </ul>;
     }
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 11eecf771..28aaf0c57 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -15,7 +15,7 @@ import { FieldId } from "../../../new_fields/RefField";
 import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
 import { TraceMobx } from '../../../new_fields/util';
 import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
-import { emptyFunction, returnOne, returnTrue, Utils } from "../../../Utils";
+import { emptyFunction, returnOne, returnTrue, Utils, returnZero } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 import { Docs } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
@@ -794,6 +794,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             ContentScaling={this.contentScaling}
             PanelWidth={this.panelWidth}
             PanelHeight={this.panelHeight}
+            NativeHeight={returnZero}
+            NativeWidth={returnZero}
             ScreenToLocalTransform={this.ScreenToLocalTransform}
             renderDepth={0}
             parentActive={returnTrue}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 3bd50ad52..cb0206260 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -4,7 +4,7 @@ import * as React from 'react';
 import { Doc, HeightSym, WidthSym } from '../../../new_fields/Doc';
 import { makeInterface } from '../../../new_fields/Schema';
 import { BoolCast, NumCast, StrCast, Cast, ScriptCast } from '../../../new_fields/Types';
-import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils, returnFalse } from '../../../Utils';
+import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils, returnFalse, returnZero } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { Transform } from '../../util/Transform';
 import "./CollectionLinearView.scss";
@@ -114,6 +114,8 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                                 onClick={undefined}
                                 ScreenToLocalTransform={this.getTransform(dref)}
                                 ContentScaling={returnOne}
+                                NativeHeight={returnZero}
+                                NativeWidth={returnZero}
                                 PanelWidth={nested ? pair.layout[WidthSym] : () => this.dimension()}// ugh - need to get rid of this inline function to avoid recomputing
                                 PanelHeight={nested ? pair.layout[HeightSym] : () => this.dimension()}
                                 renderDepth={this.props.renderDepth + 1}
@@ -123,7 +125,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                                 whenActiveChanged={emptyFunction}
                                 bringToFront={emptyFunction}
                                 ContainingCollectionView={undefined}
-                                ContainingCollectionDoc={undefined}/>
+                                ContainingCollectionDoc={undefined} />
                         </div>;
                     })}
                 </div>
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 7b16ff546..ae71c54f7 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -172,6 +172,8 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             whenActiveChanged: emptyFunction,
             PanelHeight: returnZero,
             PanelWidth: returnZero,
+            NativeHeight: returnZero,
+            NativeWidth: returnZero,
             addDocTab: this.props.addDocTab,
             pinToPres: this.props.pinToPres,
             ContentScaling: returnOne
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index d21e17bbc..8ceeb66f1 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -11,7 +11,7 @@ import { listSpec } from "../../../new_fields/Schema";
 import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types";
 import { TraceMobx } from "../../../new_fields/util";
-import { Utils, setupMoveUpEvents, emptyFunction } from "../../../Utils";
+import { Utils, setupMoveUpEvents, emptyFunction, returnZero, returnOne } from "../../../Utils";
 import { DragManager, dropActionType } from "../../util/DragManager";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
@@ -24,7 +24,7 @@ import "./CollectionStackingView.scss";
 import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn";
 import { CollectionSubView } from "./CollectionSubView";
 import { CollectionViewType } from "./CollectionView";
-import { Docs } from "../../documents/Documents";
+import { DocumentView } from "../nodes/DocumentView";
 
 @observer
 export class CollectionStackingView extends CollectionSubView(doc => doc) {
@@ -53,6 +53,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @computed get NodeWidth() { return this.props.PanelWidth() - this.gridGap; }
 
     children(docs: Doc[], columns?: number) {
+        TraceMobx();
         this._docXfs.length = 0;
         return docs.map((d, i) => {
             const height = () => this.getDocHeight(d);
@@ -115,7 +116,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     componentDidMount() {
         super.componentDidMount();
         this._heightDisposer = reaction(() => {
-            if (this.props.Document._autoHeight) {
+            if (this.props.Document._autoHeight && !this.props.NativeHeight()) {
                 const sectionsList = Array.from(this.Sections.size ? this.Sections.values() : [this.filteredChildren]);
                 if (this.isStackingView) {
                     const res = this.props.ContentScaling() * sectionsList.reduce((maxHght, s) => {
@@ -168,12 +169,13 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     getDisplayDoc(doc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) {
         const layoutDoc = Doc.Layout(doc, this.props.childLayoutTemplate?.());
         const height = () => this.getDocHeight(doc);
-        return <ContentFittingDocumentView
+        return <DocumentView
             Document={doc}
-            DataDocument={dataDoc || (doc[DataSym] !== doc && doc[DataSym])}
+            DataDoc={dataDoc || (doc[DataSym] !== doc && doc[DataSym])}
             backgroundColor={this.props.backgroundColor}
             LayoutDoc={this.props.childLayoutTemplate}
             LibraryPath={this.props.LibraryPath}
+            FreezeDimensions={this.props.freezeDimensions}
             renderDepth={this.props.renderDepth + 1}
             fitToBox={this.props.fitToBox}
             rootSelected={this.rootSelected}
@@ -181,18 +183,22 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             onClick={layoutDoc.isTemplateDoc ? this.onClickHandler : this.onChildClickHandler}
             PanelWidth={width}
             PanelHeight={height}
-            getTransform={dxf}
+            ScreenToLocalTransform={dxf}
             focus={this.props.focus}
-            CollectionDoc={this.props.CollectionView && this.props.CollectionView.props.Document}
-            CollectionView={this.props.CollectionView}
+            ContainingCollectionDoc={this.props.CollectionView && this.props.CollectionView.props.Document}
+            ContainingCollectionView={this.props.CollectionView}
             addDocument={this.props.addDocument}
             moveDocument={this.props.moveDocument}
             removeDocument={this.props.removeDocument}
-            active={this.props.active}
+            parentActive={this.props.active}
+            bringToFront={emptyFunction}
+            NativeHeight={returnZero}
+            NativeWidth={returnZero}
+            ContentScaling={returnOne}
             whenActiveChanged={this.props.whenActiveChanged}
             addDocTab={this.props.addDocTab}
             pinToPres={this.props.pinToPres}>
-        </ContentFittingDocumentView>;
+        </DocumentView>;
     }
 
     getDocWidth(d?: Doc) {
@@ -387,7 +393,11 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         return sections.map(section => this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1]));
     }
 
-    @computed get scaling() { return !this.props.Document._nativeWidth ? 1 : this.props.PanelHeight() / NumCast(this.props.Document._nativeHeight); }
+
+    @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth) || this.props.NativeWidth() || 0; }
+    @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight) || this.props.NativeHeight() || 0; }
+
+    @computed get scaling() { return !this.nativeWidth ? 1 : this.props.PanelHeight() / this.nativeHeight; }
 
     render() {
         TraceMobx();
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index d1d6ae3c1..32449de5e 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -36,12 +36,15 @@ export interface CollectionViewProps extends FieldViewProps {
     setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
     rootSelected: () => boolean;
     fieldKey: string;
+    NativeWidth: () => number;
+    NativeHeight: () => number;
 }
 
 export interface SubCollectionViewProps extends CollectionViewProps {
     CollectionView: Opt<CollectionView>;
     children?: never | (() => JSX.Element[]) | React.ReactNode;
-    overrideDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explict list (see LinkBox)
+    freezeDimensions?: boolean; // used by TimeView to coerce documents to treat their width height as their native width/height
+    overrideDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox)
     ignoreFields?: string[]; // used in TreeView to ignore specified fields (see LinkBox)
     isAnnotationOverlay?: boolean;
     annotationsKey: string;
@@ -213,9 +216,6 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                 this.props.Document.dropConverter.script.run({ dragData: docDragData }); /// bcz: check this 
             if (docDragData) {
                 let added = false;
-                if (this.props.Document._freezeOnDrop) {
-                    de.complete.docDragData?.droppedDocuments.forEach(drop => Doc.freezeNativeDimensions(drop, drop[WidthSym](), drop[HeightSym]()));
-                }
                 if (docDragData.dropAction || docDragData.userDropAction) {
                     added = docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false);
                 } else if (docDragData.moveDocument) {
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 4f77e8b0e..d9a10cdc8 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -5,7 +5,7 @@ import { List } from "../../../new_fields/List";
 import { ObjectField } from "../../../new_fields/ObjectField";
 import { RichTextField } from "../../../new_fields/RichTextField";
 import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
-import { NumCast, StrCast } from "../../../new_fields/Types";
+import { NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
 import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../../Utils";
 import { Scripting } from "../../util/Scripting";
 import { ContextMenu } from "../ContextMenu";
@@ -29,7 +29,6 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
         this.props.Document.onChildClick = undefined;
     }
     componentDidMount() {
-        this.props.Document._freezeOnDrop = true;
         const childDetailed = this.props.Document.childDetailed; // bcz: needs to be here to make sure the childDetailed layout template has been loaded when the first item is clicked;
         const childText = "const alias = getAlias(this); Doc.ApplyTemplateTo(containingCollection.childDetailed, alias, 'layout_detailView'); alias.layoutKey='layout_detailedView'; alias.dropAction='alias'; alias.removeDropProperties=new List<string>(['dropAction']); useRightSplit(alias, shiftKey); ";
         this.props.Document.onChildClick = ScriptField.MakeScript(childText, { this: Doc.name, heading: "string", containingCollection: Doc.name, shiftKey: "boolean" });
@@ -73,7 +72,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
 
     @computed get contents() {
         return <div className="collectionTimeView-innards" key="timeline" style={{ width: "100%" }}>
-            <CollectionFreeFormView  {...this.props} layoutEngine={this.layoutEngine} />
+            <CollectionFreeFormView {...this.props} freezeDimensions={BoolCast(this.layoutDoc._freezeChildDimensions, true)} layoutEngine={this.layoutEngine} />
         </div>;
     }
 
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 77dd9a162..10da50e35 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -465,6 +465,8 @@ class TreeView extends React.Component<TreeViewProps> {
                         ContentScaling={returnOne}
                         PanelWidth={returnZero}
                         PanelHeight={returnZero}
+                        NativeHeight={returnZero}
+                        NativeWidth={returnZero}
                         renderDepth={1}
                         focus={emptyFunction}
                         parentActive={returnTrue}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index a727da267..5d08a2bd8 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -13,7 +13,7 @@ import { List } from '../../../new_fields/List';
 import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from '../../../new_fields/Types';
 import { ImageField } from '../../../new_fields/URLField';
 import { TraceMobx } from '../../../new_fields/util';
-import { Utils, setupMoveUpEvents, returnFalse } from '../../../Utils';
+import { Utils, setupMoveUpEvents, returnFalse, returnZero } from '../../../Utils';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { DocumentManager } from '../../util/DocumentManager';
 import { ImageUtils } from '../../util/Import & Export/ImageUtils';
@@ -424,6 +424,8 @@ export class CollectionView extends Touchable<FieldViewProps> {
                     <CollectionTreeView {...this.props}
                         CollectionView={this}
                         treeViewHideTitle={true}
+                        NativeHeight={returnZero}
+                        NativeWidth={returnZero}
                         treeViewHideHeaderFields={true}
                         onCheckedClick={this.scriptField!}
                         ignoreFields={this.treeIgnoreFields}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index d4e44b9a9..f22f1a304 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -89,8 +89,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     @computed get fitToContent() { return (this.props.fitToBox || this.Document._fitToBox) && !this.isAnnotationOverlay; }
     @computed get parentScaling() { return this.props.ContentScaling && this.fitToContent && !this.isAnnotationOverlay ? this.props.ContentScaling() : 1; }
     @computed get contentBounds() { return aggregateBounds(this._layoutElements.filter(e => e.bounds && !e.bounds.z).map(e => e.bounds!), NumCast(this.layoutDoc.xPadding, 10), NumCast(this.layoutDoc.yPadding, 10)); }
-    @computed get nativeWidth() { return this.Document._fitToContent ? 0 : NumCast(this.Document._nativeWidth); }
-    @computed get nativeHeight() { return this.fitToContent ? 0 : NumCast(this.Document._nativeHeight); }
+    @computed get nativeWidth() { return this.Document._fitToContent ? 0 : NumCast(this.Document._nativeWidth, this.props.NativeWidth()); }
+    @computed get nativeHeight() { return this.fitToContent ? 0 : NumCast(this.Document._nativeHeight, this.props.NativeHeight()); }
     private get isAnnotationOverlay() { return this.props.isAnnotationOverlay; }
     private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; }
     private easing = () => this.props.Document.panTransformType === "Ease";
@@ -825,6 +825,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             DataDoc: childData,
             Document: childLayout,
             LibraryPath: this.libraryPath,
+            FreezeDimensions: this.props.freezeDimensions,
             layoutKey: undefined,
             rootSelected: this.rootSelected,
             dropAction: StrCast(this.props.Document.childDropAction) as dropActionType,
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index be0e1aec4..ff9630273 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -7,7 +7,7 @@ import { AudioField, nullAudio } from "../../../new_fields/URLField";
 import { DocExtendableComponent } from "../DocComponent";
 import { makeInterface, createSchema } from "../../../new_fields/Schema";
 import { documentSchema } from "../../../new_fields/documentSchemas";
-import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse } from "../../../Utils";
+import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse, returnZero } from "../../../Utils";
 import { runInAction, observable, reaction, IReactionDisposer, computed, action } from "mobx";
 import { DateField } from "../../../new_fields/DateField";
 import { SelectionManager } from "../../util/SelectionManager";
@@ -261,6 +261,8 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
                                         <div className={this.props.PanelHeight() < 32 ? "audioBox-linker-mini" : "audioBox-linker"} key={"linker" + i}>
                                             <DocumentView {...this.props}
                                                 Document={l}
+                                                NativeHeight={returnZero}
+                                                NativeWidth={returnZero}
                                                 rootSelected={returnFalse}
                                                 layoutKey={Doc.LinkEndpoint(l, la2)}
                                                 ContainingCollectionDoc={this.props.Document}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 356192797..8a4842427 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -41,10 +41,11 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
         const hgt = this.renderScriptDim ? this.renderScriptDim.height : this.props.height !== undefined ? this.props.height : this.props.dataProvider && this.dataProvider ? this.dataProvider.height : this.layoutDoc[HeightSym]();
         return (hgt === undefined && this.nativeWidth && this.nativeHeight) ? this.width * this.nativeHeight / this.nativeWidth : hgt;
     }
+    @computed get freezeDimensions() { return this.props.FreezeDimensions || this.layoutDoc._freezeChildDimensions; }
     @computed get dataProvider() { return this.props.dataProvider && this.props.dataProvider(this.props.Document) ? this.props.dataProvider(this.props.Document) : undefined; }
-    @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth); }
-    @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight); }
-
+    @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
+    @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
+   
     @computed get renderScriptDim() {
         if (this.Document.renderScript) {
             const someView = Cast(this.props.Document.someView, Doc);
@@ -68,6 +69,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
         .scale(1 / this.contentScaling())
 
     focusDoc = (doc: Doc) => this.props.focus(doc, false);
+    NativeWidth = () => this.nativeWidth;
+    NativeHeight = () => this.nativeHeight;
     render() {
         TraceMobx();
         return <div className="collectionFreeFormDocumentView-container"
@@ -89,22 +92,26 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 pointerEvents: this.props.Document.isBackground ? "none" : undefined
             }} >
 
-            {!this.props.fitToBox ? 
-            <DocumentView {...this.props}
-                dragDivName={"collectionFreeFormDocumentView-container"}
-                ContentScaling={this.contentScaling}
-                ScreenToLocalTransform={this.getTransform}
-                backgroundColor={this.props.backgroundColor}
-                PanelWidth={this.panelWidth}
-                PanelHeight={this.panelHeight} /> 
-            : <ContentFittingDocumentView {...this.props}
-                CollectionDoc={this.props.ContainingCollectionDoc}
-                DataDocument={this.props.DataDoc}
-                getTransform={this.getTransform}
-                active={returnFalse}
-                focus={this.focusDoc}
-                PanelWidth={this.panelWidth}
-                PanelHeight={this.panelHeight}
+            {!this.props.fitToBox ?
+                <DocumentView {...this.props}
+                    dragDivName={"collectionFreeFormDocumentView-container"}
+                    ContentScaling={this.contentScaling}
+                    ScreenToLocalTransform={this.getTransform}
+                    backgroundColor={this.props.backgroundColor}
+                    NativeHeight={this.NativeHeight}
+                    NativeWidth={this.NativeWidth}
+                    PanelWidth={this.panelWidth}
+                    PanelHeight={this.panelHeight} />
+                : <ContentFittingDocumentView {...this.props}
+                    CollectionDoc={this.props.ContainingCollectionDoc}
+                    DataDocument={this.props.DataDoc}
+                    getTransform={this.getTransform}
+                    NativeHeight={this.NativeHeight}
+                    NativeWidth={this.NativeWidth}
+                    active={returnFalse}
+                    focus={this.focusDoc}
+                    PanelWidth={this.panelWidth}
+                    PanelHeight={this.panelHeight}
                 />}
         </div>;
     }
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 9ab6826a3..09675bf73 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -18,6 +18,9 @@ interface ContentFittingDocumentViewProps {
     Document?: Doc;
     DataDocument?: Doc;
     LayoutDoc?: () => Opt<Doc>;
+    NativeWidth?: () => number;
+    NativeHeight?: () => number;
+    FreezeDimensions?: boolean;
     LibraryPath: Doc[];
     childDocs?: Doc[];
     renderDepth: number;
@@ -47,12 +50,12 @@ interface ContentFittingDocumentViewProps {
 export class ContentFittingDocumentView extends React.Component<ContentFittingDocumentViewProps>{
     public get displayName() { return "DocumentView(" + this.props.Document?.title + ")"; } // this makes mobx trace() statements more descriptive
     private get layoutDoc() { return this.props.Document && (this.props.LayoutDoc?.() || Doc.Layout(this.props.Document)); }
-    private get nativeWidth() { return NumCast(this.layoutDoc?._nativeWidth, this.props.PanelWidth()); }
-    private get nativeHeight() { return NumCast(this.layoutDoc?._nativeHeight, this.props.PanelHeight()); }
+    private nativeWidth = () => NumCast(this.layoutDoc?._nativeWidth, this.props.NativeWidth?.() || this.props.PanelWidth());
+    private nativeHeight = () => NumCast(this.layoutDoc?._nativeHeight, this.props.NativeHeight?.() || this.props.PanelHeight());
     @computed get scaling() {
-        const wscale = this.props.PanelWidth() / (this.nativeWidth || this.props.PanelWidth() || 1);
-        if (wscale * this.nativeHeight > this.props.PanelHeight()) {
-            return (this.props.PanelHeight() / (this.nativeHeight || this.props.PanelHeight() || 1)) || 1;
+        const wscale = this.props.PanelWidth() / (this.nativeWidth() || this.props.PanelWidth() || 1);
+        if (wscale * this.nativeHeight() > this.props.PanelHeight()) {
+            return (this.props.PanelHeight() / (this.nativeHeight() || this.props.PanelHeight() || 1)) || 1;
         }
         return wscale || 1;
     }
@@ -61,12 +64,12 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
     private PanelWidth = () => this.panelWidth;
     private PanelHeight = () => this.panelHeight;
 
-    @computed get panelWidth() { return this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeWidth * this.contentScaling() : this.props.PanelWidth(); }
-    @computed get panelHeight() { return this.nativeHeight && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeHeight * this.contentScaling() : this.props.PanelHeight(); }
+    @computed get panelWidth() { return this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeWidth() * this.contentScaling() : this.props.PanelWidth(); }
+    @computed get panelHeight() { return this.nativeHeight && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeHeight() * this.contentScaling() : this.props.PanelHeight(); }
 
     private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, -this.centeringYOffset).scale(1 / this.contentScaling());
-    private get centeringOffset() { return this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? (this.props.PanelWidth() - this.nativeWidth * this.contentScaling()) / 2 : 0; }
-    private get centeringYOffset() { return Math.abs(this.centeringOffset) < 0.001 ? (this.props.PanelHeight() - this.nativeHeight * this.contentScaling()) / 2 : 0; }
+    private get centeringOffset() { return this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? (this.props.PanelWidth() - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
+    private get centeringYOffset() { return Math.abs(this.centeringOffset) < 0.001 ? (this.props.PanelHeight() - this.nativeHeight() * this.contentScaling()) / 2 : 0; }
 
     @computed get borderRounding() { return StrCast(this.props.Document?.borderRounding); }
 
@@ -81,7 +84,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                     style={{
                         transform: `translate(${this.centeringOffset}px, 0px)`,
                         borderRadius: this.borderRounding,
-                        height: Math.abs(this.centeringYOffset) > 0.001 ? `${100 * this.nativeHeight / this.nativeWidth * this.props.PanelWidth() / this.props.PanelHeight()}%` : this.props.PanelHeight(),
+                        height: Math.abs(this.centeringYOffset) > 0.001 ? `${100 * this.nativeHeight() / this.nativeWidth() * this.props.PanelWidth() / this.props.PanelHeight()}%` : this.props.PanelHeight(),
                         width: Math.abs(this.centeringOffset) > 0.001 ? `${100 * (this.props.PanelWidth() - this.centeringOffset * 2) / this.props.PanelWidth()}%` : this.props.PanelWidth()
                     }}>
                     <DocumentView {...this.props}
@@ -89,6 +92,8 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         DataDoc={this.props.DataDocument}
                         LayoutDoc={this.props.LayoutDoc}
                         LibraryPath={this.props.LibraryPath}
+                        NativeWidth={this.nativeWidth}
+                        NativeHeight={this.nativeHeight}
                         fitToBox={this.props.fitToBox}
                         layoutKey={this.props.layoutKey}
                         dropAction={this.props.dropAction}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index aa3c1b3a2..9c9f2e48e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -3,7 +3,7 @@ import * as fa from '@fortawesome/free-solid-svg-icons';
 import { action, computed, runInAction, trace, observable } from "mobx";
 import { observer } from "mobx-react";
 import * as rp from "request-promise";
-import { Doc, DocListCast, Opt } from "../../../new_fields/Doc";
+import { Doc, DocListCast, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc";
 import { Document, PositionDocument } from '../../../new_fields/documentSchemas';
 import { Id } from '../../../new_fields/FieldSymbols';
 import { InkTool } from '../../../new_fields/InkField';
@@ -56,6 +56,9 @@ export type DocFocusFunc = () => boolean;
 export interface DocumentViewProps {
     ContainingCollectionView: Opt<CollectionView>;
     ContainingCollectionDoc: Opt<Doc>;
+    FreezeDimensions?: boolean;
+    NativeWidth: () => number;
+    NativeHeight: () => number;
     Document: Doc;
     DataDoc?: Doc;
     LayoutDoc?: () => Opt<Doc>;
@@ -109,11 +112,14 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     public get ContentDiv() { return this._mainCont.current; }
     @computed get active() { return SelectionManager.IsSelected(this, true) || this.props.parentActive(true); }
     @computed get topMost() { return this.props.renderDepth === 0; }
-    @computed get nativeWidth() { return this.layoutDoc._nativeWidth || 0; }
-    @computed get nativeHeight() { return this.layoutDoc._nativeHeight || 0; }
+    @computed get freezeDimensions() { return this.props.FreezeDimensions || this.layoutDoc._freezeChildDimensions; }
+    @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
+    @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
     @computed get onClickHandler() { return this.props.onClick || this.layoutDoc.onClick || this.Document.onClick; }
     @computed get onPointerDownHandler() { return this.props.onPointerDown ? this.props.onPointerDown : this.Document.onPointerDown; }
     @computed get onPointerUpHandler() { return this.props.onPointerUp ? this.props.onPointerUp : this.Document.onPointerUp; }
+    NativeWidth = () => this.nativeWidth;
+    NativeHeight = () => this.nativeHeight;
 
     private _firstX: number = -1;
     private _firstY: number = -1;
@@ -965,6 +971,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         TraceMobx();
         return (<DocumentContentsView ContainingCollectionView={this.props.ContainingCollectionView}
             ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+            NativeHeight={this.NativeHeight}
+            NativeWidth={this.NativeWidth}
             Document={this.props.Document}
             DataDoc={this.props.DataDoc}
             LayoutDoc={this.props.LayoutDoc}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 13a1becf7..dfcb03985 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -45,6 +45,8 @@ export interface FieldViewProps {
     focus: (doc: Doc) => void;
     PanelWidth: () => number;
     PanelHeight: () => number;
+    NativeHeight: () => number;
+    NativeWidth: () => number;
     setVideoBox?: (player: VideoBox) => void;
     ContentScaling: () => number;
     ChromeHeight?: () => number;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 94195fbd6..37770a2e1 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -22,7 +22,7 @@ import { RichTextUtils } from '../../../new_fields/RichTextUtils';
 import { createSchema, makeInterface } from "../../../new_fields/Schema";
 import { Cast, NumCast, StrCast, BoolCast, DateCast } from "../../../new_fields/Types";
 import { TraceMobx } from '../../../new_fields/util';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, Utils, returnTrue } from '../../../Utils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, Utils, returnTrue, returnZero } from '../../../Utils';
 import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/GoogleApiClientUtils';
 import { DocServer } from "../../DocServer";
 import { Docs, DocUtils } from '../../documents/Documents';
@@ -1216,6 +1216,8 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
                         <CollectionFreeFormView {...this.props}
                             PanelHeight={this.props.PanelHeight}
                             PanelWidth={this.sidebarWidth}
+                            NativeHeight={returnZero}
+                            NativeWidth={returnZero}
                             annotationsKey={this.annotationKey}
                             isAnnotationOverlay={false}
                             focus={this.props.focus}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 00057055f..a4d3f3d79 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -14,7 +14,7 @@ import { ComputedField } from '../../../new_fields/ScriptField';
 import { Cast, NumCast, StrCast } from '../../../new_fields/Types';
 import { AudioField, ImageField } from '../../../new_fields/URLField';
 import { TraceMobx } from '../../../new_fields/util';
-import { emptyFunction, returnOne, Utils } from '../../../Utils';
+import { emptyFunction, returnOne, Utils, returnZero } from '../../../Utils';
 import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices';
 import { Docs } from '../../documents/Documents';
 import { Networking } from '../../Network';
@@ -445,6 +445,8 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
             <CollectionFreeFormView {...this.props}
                 PanelHeight={this.props.PanelHeight}
                 PanelWidth={this.props.PanelWidth}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
                 annotationsKey={this.annotationKey}
                 isAnnotationOverlay={true}
                 focus={this.props.focus}
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index ef039c857..6dc4ae578 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -62,13 +62,15 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             rootSelected: returnFalse,
             isSelected: returnFalse,
             select: emptyFunction,
-            dropAction:"alias",
-            bringToFront:emptyFunction,
+            dropAction: "alias",
+            bringToFront: emptyFunction,
             renderDepth: 1,
             active: returnFalse,
             whenActiveChanged: emptyFunction,
             ScreenToLocalTransform: Transform.Identity,
             focus: emptyFunction,
+            NativeHeight: returnZero,
+            NativeWidth: returnZero,
             PanelWidth: this.props.PanelWidth,
             PanelHeight: this.props.PanelHeight,
             addDocTab: returnFalse,
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 0e327e130..542c86049 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -23,6 +23,8 @@ export class LinkBox extends DocExtendableComponent<FieldViewProps, LinkDocument
             <CollectionTreeView {...this.props}
                 ChromeHeight={returnZero}
                 overrideDocuments={[this.dataDoc]}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
                 ignoreFields={Cast(this.props.Document.linkBoxExcludedKeys, listSpec("string"), null)}
                 annotationsKey={""}
                 CollectionView={undefined}
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 7c58a5148..58ff4971a 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -10,7 +10,7 @@ import { makeInterface } from "../../../new_fields/Schema";
 import { ScriptField } from "../../../new_fields/ScriptField";
 import { Cast, StrCast } from "../../../new_fields/Types";
 import { VideoField } from "../../../new_fields/URLField";
-import { emptyFunction, returnFalse, returnOne, Utils } from "../../../Utils";
+import { emptyFunction, returnFalse, returnOne, Utils, returnZero } from "../../../Utils";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
 import { ContextMenu } from "../ContextMenu";
@@ -170,6 +170,8 @@ export class ScreenshotBox extends DocAnnotatableComponent<FieldViewProps, Scree
                 <CollectionFreeFormView {...this.props}
                     PanelHeight={this.props.PanelHeight}
                     PanelWidth={this.props.PanelWidth}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
                     annotationsKey={this.annotationKey}
                     focus={this.props.focus}
                     isSelected={this.props.isSelected}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 24b66d8f7..d384ad12f 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -11,7 +11,7 @@ import { createSchema, makeInterface } from "../../../new_fields/Schema";
 import { ScriptField } from "../../../new_fields/ScriptField";
 import { Cast, StrCast, NumCast } from "../../../new_fields/Types";
 import { VideoField } from "../../../new_fields/URLField";
-import { Utils, emptyFunction, returnOne } from "../../../Utils";
+import { Utils, emptyFunction, returnOne, returnZero } from "../../../Utils";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
 import { ContextMenu } from "../ContextMenu";
@@ -352,6 +352,8 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
                 <CollectionFreeFormView {...this.props}
                     PanelHeight={this.props.PanelHeight}
                     PanelWidth={this.props.PanelWidth}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
                     annotationsKey={this.annotationKey}
                     focus={this.props.focus}
                     isSelected={this.props.isSelected}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 838fbefb1..ea5d601ec 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -9,7 +9,7 @@ import { InkTool } from "../../../new_fields/InkField";
 import { makeInterface } from "../../../new_fields/Schema";
 import { Cast, NumCast } from "../../../new_fields/Types";
 import { WebField } from "../../../new_fields/URLField";
-import { Utils, returnOne, emptyFunction } from "../../../Utils";
+import { Utils, returnOne, emptyFunction, returnZero } from "../../../Utils";
 import { Docs } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
 import { ImageUtils } from "../../util/Import & Export/ImageUtils";
@@ -335,6 +335,8 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
                 PanelHeight={this.props.PanelHeight}
                 PanelWidth={this.props.PanelWidth}
                 annotationsKey={this.annotationKey}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
                 focus={this.props.focus}
                 isSelected={this.props.isSelected}
                 isAnnotationOverlay={true}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 25ceb6218..36e687f71 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -9,7 +9,7 @@ import { List } from "../../../new_fields/List";
 import { makeInterface, createSchema } from "../../../new_fields/Schema";
 import { ScriptField, ComputedField } from "../../../new_fields/ScriptField";
 import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { smoothScroll, Utils, emptyFunction, returnOne, intersectRect, addStyleSheet, addStyleSheetRule, clearStyleSheetRules } from "../../../Utils";
+import { smoothScroll, Utils, emptyFunction, returnOne, intersectRect, addStyleSheet, addStyleSheetRule, clearStyleSheetRules, returnZero } from "../../../Utils";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
 import { CompiledScript, CompileScript } from "../../util/Scripting";
@@ -648,6 +648,8 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
                 setPreviewCursor={this.setPreviewCursor}
                 PanelHeight={this.panelWidth}
                 PanelWidth={this.panelHeight}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
                 dropAction={"alias"}
                 VisibleHeight={this.visibleHeight}
                 focus={this.props.focus}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 5f766c121..c87ac719c 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -7,7 +7,7 @@ import { Doc, DocListCast } from '../new_fields/Doc';
 import { Docs } from '../client/documents/Documents';
 import { CollectionView } from '../client/views/collections/CollectionView';
 import { DocumentView } from '../client/views/nodes/DocumentView';
-import { emptyPath, emptyFunction, returnFalse, returnOne, returnEmptyString, returnTrue } from '../Utils';
+import { emptyPath, emptyFunction, returnFalse, returnOne, returnEmptyString, returnTrue, returnZero } from '../Utils';
 import { Transform } from '../client/util/Transform';
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faPenNib, faHighlighter, faEraser, faMousePointer, faBreadSlice, faTrash, faCheck, faLongArrowAltLeft } from '@fortawesome/free-solid-svg-icons';
@@ -129,6 +129,8 @@ export default class MobileInterface extends React.Component {
                 onClick={undefined}
                 ScreenToLocalTransform={Transform.Identity}
                 ContentScaling={returnOne}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
                 PanelWidth={() => window.screen.width}
                 PanelHeight={() => window.screen.height}
                 renderDepth={0}
@@ -173,6 +175,8 @@ export default class MobileInterface extends React.Component {
         e.stopPropagation();
     }
 
+    panelHeight = () => window.innerHeight;
+    panelWidth = () => window.innerWidth;
     renderInkingContent = () => {
         console.log("rendering inking content");
         // TODO: support panning and zooming
@@ -201,8 +205,10 @@ export default class MobileInterface extends React.Component {
                         bringToFront={emptyFunction}
                         addDocTab={returnFalse}
                         pinToPres={emptyFunction}
-                        PanelHeight={() => window.innerHeight}
-                        PanelWidth={() => window.innerWidth}
+                        PanelWidth={this.panelWidth}
+                        PanelHeight={this.panelHeight}
+                        NativeHeight={returnZero}
+                        NativeWidth={returnZero}
                         focus={emptyFunction}
                         isSelected={returnFalse}
                         select={emptyFunction}
@@ -289,6 +295,8 @@ export default class MobileInterface extends React.Component {
                         onClick={undefined}
                         ScreenToLocalTransform={Transform.Identity}
                         ContentScaling={returnOne}
+                        NativeHeight={returnZero}
+                        NativeWidth={returnZero}
                         PanelWidth={() => window.screen.width}
                         PanelHeight={() => window.screen.height}
                         renderDepth={0}
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index 1a5a471a0..ff02596f7 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -28,7 +28,7 @@ export const documentSchema = createSchema({
     _pivotField: "string",      // specifies which field should be used as the timeline/pivot axis
     _replacedChrome: "string",  // what the default chrome is replaced with. Currently only supports the value of 'replaced' for PresBox's.
     _chromeStatus: "string",    // determines the state of the collection chrome. values allowed are 'replaced', 'enabled', 'disabled', 'collapsed'
-    _freezeOnDrop: "boolean",    // whether a document without native dimensions should have its width/height frozen as native dimensions on drop.  Used by Timeline view to make sure documents are scaled to fit the display thumbnail
+    _freezeChildDimensions: "boolean", // freezes child document dimensions (e.g., used by time/pivot view to make sure all children will be scaled to fit their display rectangle)
     color: "string",            // foreground color of document
     backgroundColor: "string",  // background color of document
     opacity: "number",          // opacity of document
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 8c719ccd8..480a55da0 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -12,7 +12,7 @@ function _readOnlySetter(): never {
     throw new Error("Documents can't be modified in read-only mode");
 }
 
-const tracing = false;
+const tracing = true;
 export function TraceMobx() {
     tracing && trace();
 }
-- 
cgit v1.2.3-70-g09d2


From 29640eadc13bf4dc05c128333e0060f58ace37e1 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 5 Apr 2020 16:00:49 -0400
Subject: debugging

---
 src/client/views/collections/CollectionStackingView.tsx |  1 +
 src/client/views/nodes/DocumentContentsView.tsx         | 10 ++++++++++
 src/client/views/nodes/DocumentView.tsx                 | 12 +++++++-----
 3 files changed, 18 insertions(+), 5 deletions(-)

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 8ceeb66f1..b11baeb7a 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -47,6 +47,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; }
     @computed get showAddAGroup() { return (this.pivotField && (this.props.Document._chromeStatus !== 'view-mode' && this.props.Document._chromeStatus !== 'disabled')); }
     @computed get columnWidth() {
+        TraceMobx();
         return Math.min(this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin,
             this.isStackingView ? Number.MAX_VALUE : NumCast(this.props.Document.columnWidth, 250));
     }
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index dc71ba280..4b6729fe7 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -63,6 +63,16 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
     hideOnLeave?: boolean,
     makeLink?: () => Opt<Doc>,  // function to call when a link is made
 }> {
+    constructor(props: any) {
+        super(props);
+        console.log("Consructr" + this.props.Document.title);
+    }
+    componentWillUpdate() {
+        console.log("WillUpdate" + this.props.Document.title);
+    }
+    componentWillReceiveProps() {
+        console.log("Receive" + this.props.Document.title);
+    }
     @computed get layout(): string {
         TraceMobx();
         if (!this.layoutDoc) return "<p>awaiting layout</p>";
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 9c9f2e48e..eceda4a18 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -14,7 +14,7 @@ import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
 import { AudioField, ImageField, PdfField, VideoField } from '../../../new_fields/URLField';
 import { TraceMobx } from '../../../new_fields/util';
 import { GestureUtils } from '../../../pen-gestures/GestureUtils';
-import { emptyFunction, returnOne, returnTransparent, returnTrue, Utils, OmitKeys } from "../../../Utils";
+import { emptyFunction, returnOne, returnTransparent, returnTrue, Utils, OmitKeys, returnZero } from "../../../Utils";
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { DocServer } from "../../DocServer";
 import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents";
@@ -113,8 +113,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     @computed get active() { return SelectionManager.IsSelected(this, true) || this.props.parentActive(true); }
     @computed get topMost() { return this.props.renderDepth === 0; }
     @computed get freezeDimensions() { return this.props.FreezeDimensions || this.layoutDoc._freezeChildDimensions; }
-    @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
-    @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
+    @computed get nativeWidth() { return this.layoutDoc._nativeWidth || 0; }
+    @computed get nativeHeight() { return this.layoutDoc._nativeHeight || 0; }
+    // @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
+    // @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
     @computed get onClickHandler() { return this.props.onClick || this.layoutDoc.onClick || this.Document.onClick; }
     @computed get onPointerDownHandler() { return this.props.onPointerDown ? this.props.onPointerDown : this.Document.onPointerDown; }
     @computed get onPointerUpHandler() { return this.props.onPointerUp ? this.props.onPointerUp : this.Document.onPointerUp; }
@@ -971,8 +973,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         TraceMobx();
         return (<DocumentContentsView ContainingCollectionView={this.props.ContainingCollectionView}
             ContainingCollectionDoc={this.props.ContainingCollectionDoc}
-            NativeHeight={this.NativeHeight}
-            NativeWidth={this.NativeWidth}
+            NativeHeight={returnZero}
+            NativeWidth={returnZero}
             Document={this.props.Document}
             DataDoc={this.props.DataDoc}
             LayoutDoc={this.props.LayoutDoc}
-- 
cgit v1.2.3-70-g09d2


From 881a522e1562f948202fcdb6a5a87485bf778597 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 5 Apr 2020 18:30:46 -0400
Subject: more fixes to NativeWidth/Height & FreezeDimensions props stuff

---
 .../views/collections/CollectionSchemaView.tsx      | 11 +++++++----
 .../views/collections/CollectionStackingView.tsx    |  1 -
 .../collectionFreeForm/CollectionFreeFormView.tsx   |  8 ++++++--
 .../views/nodes/CollectionFreeFormDocumentView.tsx  |  6 +++---
 .../views/nodes/ContentFittingDocumentView.tsx      |  1 -
 src/client/views/nodes/DocumentContentsView.tsx     | 10 ----------
 src/client/views/nodes/DocumentView.tsx             | 21 +++++++++++----------
 src/client/views/nodes/ImageBox.tsx                 |  6 +++---
 8 files changed, 30 insertions(+), 34 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index a1b541f74..df9f65a21 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -28,7 +28,8 @@ import "./CollectionSchemaView.scss";
 import { CollectionSubView } from "./CollectionSubView";
 import { CollectionView } from "./CollectionView";
 import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
-import { setupMoveUpEvents, emptyFunction } from "../../../Utils";
+import { setupMoveUpEvents, emptyFunction, returnZero, returnOne } from "../../../Utils";
+import { DocumentView } from "../nodes/DocumentView";
 
 library.add(faCog, faPlus, faSortUp, faSortDown);
 library.add(faTable);
@@ -117,12 +118,14 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
 
     @computed
     get previewPanel() {
-        return <div ref={this.createTarget}>
+        return !this.previewDocument ? (null) : <div ref={this.createTarget} style={{ width: `${this.previewWidth()}px` }}>
             <ContentFittingDocumentView
                 Document={this.previewDocument}
                 DataDocument={undefined}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
+                focus={emptyFunction}
                 LibraryPath={this.props.LibraryPath}
-                childDocs={this.childDocs}
                 renderDepth={this.props.renderDepth}
                 rootSelected={this.rootSelected}
                 PanelWidth={this.previewWidth}
@@ -180,7 +183,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
 
     render() {
         return <div className="collectionSchemaView-container">
-            <div className="collectionSchemaView-tableContainer" onPointerDown={this.onPointerDown} onWheel={e => this.props.active(true) && e.stopPropagation()} onDrop={e => this.onExternalDrop(e, {})} ref={this.createTarget}>
+            <div className="collectionSchemaView-tableContainer" style={{ width: `calc(100% - ${this.previewWidth()}px)` }} onPointerDown={this.onPointerDown} onWheel={e => this.props.active(true) && e.stopPropagation()} onDrop={e => this.onExternalDrop(e, {})} ref={this.createTarget}>
                 {this.schemaTable}
             </div>
             {this.dividerDragger}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index b11baeb7a..8ceeb66f1 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -47,7 +47,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; }
     @computed get showAddAGroup() { return (this.pivotField && (this.props.Document._chromeStatus !== 'view-mode' && this.props.Document._chromeStatus !== 'disabled')); }
     @computed get columnWidth() {
-        TraceMobx();
         return Math.min(this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin,
             this.isStackingView ? Number.MAX_VALUE : NumCast(this.props.Document.columnWidth, 250));
     }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f22f1a304..ceec9dfcc 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -952,11 +952,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         const elements: ViewDefResult[] = computedElementData.slice();
         this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).forEach(pair =>
             elements.push({
-                ele: <CollectionFreeFormDocumentView key={pair.layout[Id]}  {...this.getChildDocumentViewProps(pair.layout, pair.data)}
+                ele: <CollectionFreeFormDocumentView
+                    key={pair.layout[Id]}
+                    {...this.getChildDocumentViewProps(pair.layout, pair.data)}
                     dataProvider={this.childDataProvider}
                     LayoutDoc={this.childLayoutDocFunc}
                     jitterRotation={NumCast(this.props.Document.jitterRotation)}
-                    fitToBox={this.props.fitToBox || this.props.layoutEngine !== undefined} />,
+                    fitToBox={this.props.fitToBox || this.props.layoutEngine !== undefined}
+                    FreezeDimensions={this.props.layoutEngine !== undefined}
+                />,
                 bounds: this.childDataProvider(pair.layout)
             }));
 
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 8a4842427..e4c8bbd7b 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -41,11 +41,11 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
         const hgt = this.renderScriptDim ? this.renderScriptDim.height : this.props.height !== undefined ? this.props.height : this.props.dataProvider && this.dataProvider ? this.dataProvider.height : this.layoutDoc[HeightSym]();
         return (hgt === undefined && this.nativeWidth && this.nativeHeight) ? this.width * this.nativeHeight / this.nativeWidth : hgt;
     }
-    @computed get freezeDimensions() { return this.props.FreezeDimensions || this.layoutDoc._freezeChildDimensions; }
+    @computed get freezeDimensions() { return this.props.FreezeDimensions; }
     @computed get dataProvider() { return this.props.dataProvider && this.props.dataProvider(this.props.Document) ? this.props.dataProvider(this.props.Document) : undefined; }
     @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
     @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
-   
+
     @computed get renderScriptDim() {
         if (this.Document.renderScript) {
             const someView = Cast(this.props.Document.someView, Doc);
@@ -61,7 +61,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
         return undefined;
     }
 
-    contentScaling = () => this.nativeWidth > 0 && !this.props.fitToBox ? this.width / this.nativeWidth : 1;
+    contentScaling = () => this.nativeWidth > 0 && !this.props.fitToBox && !this.freezeDimensions ? this.width / this.nativeWidth : 1;
     panelWidth = () => (this.dataProvider?.width || this.props.PanelWidth());
     panelHeight = () => (this.dataProvider?.height || this.props.PanelHeight());
     getTransform = (): Transform => this.props.ScreenToLocalTransform()
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 09675bf73..52e5ed1dd 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -22,7 +22,6 @@ interface ContentFittingDocumentViewProps {
     NativeHeight?: () => number;
     FreezeDimensions?: boolean;
     LibraryPath: Doc[];
-    childDocs?: Doc[];
     renderDepth: number;
     fitToBox?: boolean;
     layoutKey?: string;
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 4b6729fe7..dc71ba280 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -63,16 +63,6 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
     hideOnLeave?: boolean,
     makeLink?: () => Opt<Doc>,  // function to call when a link is made
 }> {
-    constructor(props: any) {
-        super(props);
-        console.log("Consructr" + this.props.Document.title);
-    }
-    componentWillUpdate() {
-        console.log("WillUpdate" + this.props.Document.title);
-    }
-    componentWillReceiveProps() {
-        console.log("Receive" + this.props.Document.title);
-    }
     @computed get layout(): string {
         TraceMobx();
         if (!this.layoutDoc) return "<p>awaiting layout</p>";
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index eceda4a18..d800579a1 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -112,11 +112,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     public get ContentDiv() { return this._mainCont.current; }
     @computed get active() { return SelectionManager.IsSelected(this, true) || this.props.parentActive(true); }
     @computed get topMost() { return this.props.renderDepth === 0; }
-    @computed get freezeDimensions() { return this.props.FreezeDimensions || this.layoutDoc._freezeChildDimensions; }
-    @computed get nativeWidth() { return this.layoutDoc._nativeWidth || 0; }
-    @computed get nativeHeight() { return this.layoutDoc._nativeHeight || 0; }
-    // @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
-    // @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
+    @computed get freezeDimensions() { return this.props.FreezeDimensions; }
+    @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
+    @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
     @computed get onClickHandler() { return this.props.onClick || this.layoutDoc.onClick || this.Document.onClick; }
     @computed get onPointerDownHandler() { return this.props.onPointerDown ? this.props.onPointerDown : this.Document.onPointerDown; }
     @computed get onPointerUpHandler() { return this.props.onPointerUp ? this.props.onPointerUp : this.Document.onPointerUp; }
@@ -969,12 +967,15 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         return this.isSelected(false) || (this.props.Document.forceActive && this.props.rootSelected?.() ? true : false);
     }
     childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
+    panelWidth = () => this.props.PanelWidth();
+    panelHeight = () => this.props.PanelHeight();
+    screenToLocalTransform = () => this.props.ScreenToLocalTransform();
     @computed get contents() {
         TraceMobx();
         return (<DocumentContentsView ContainingCollectionView={this.props.ContainingCollectionView}
             ContainingCollectionDoc={this.props.ContainingCollectionDoc}
-            NativeHeight={returnZero}
-            NativeWidth={returnZero}
+            NativeWidth={this.NativeWidth}
+            NativeHeight={this.NativeHeight}
             Document={this.props.Document}
             DataDoc={this.props.DataDoc}
             LayoutDoc={this.props.LayoutDoc}
@@ -985,10 +986,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             addDocument={this.props.addDocument}
             removeDocument={this.props.removeDocument}
             moveDocument={this.props.moveDocument}
-            ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+            ScreenToLocalTransform={this.screenToLocalTransform}
             renderDepth={this.props.renderDepth}
-            PanelWidth={this.props.PanelWidth}
-            PanelHeight={this.props.PanelHeight}
+            PanelWidth={this.panelWidth}
+            PanelHeight={this.panelHeight}
             focus={this.props.focus}
             parentActive={this.props.parentActive}
             whenActiveChanged={this.props.whenActiveChanged}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index a4d3f3d79..052251d94 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -436,9 +436,9 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
         const dragging = !SelectionManager.GetIsDragging() ? "" : "-dragging";
         return (<div className={`imageBox${dragging}`} onContextMenu={this.specificContextMenu}
             style={{
-                transform: `scale(${this.props.ContentScaling()})`,
-                width: `${100 / this.props.ContentScaling()}%`,
-                height: `${100 / this.props.ContentScaling()}%`,
+                transform: this.props.PanelWidth() ? undefined : `scale(${this.props.ContentScaling()})`,
+                width: this.props.PanelWidth() ? `${this.props.PanelWidth()}px` : `${100 / this.props.ContentScaling()}%`,
+                height: this.props.PanelWidth() ? undefined : `${100 / this.props.ContentScaling()}%`,
                 pointerEvents: this.props.Document.isBackground ? "none" : undefined,
                 borderRadius: `${Number(StrCast(this.layoutDoc.borderRounding).replace("px", "")) / this.props.ContentScaling()}px`
             }} >
-- 
cgit v1.2.3-70-g09d2


From bc23e69a88234c213e444b1aa3c5eb895c35aca9 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 6 Apr 2020 00:23:19 -0400
Subject: many more fixes to nativewidth/height layout changes.

---
 .../views/collections/CollectionSchemaView.tsx     | 51 ++++++++++++----------
 .../views/collections/CollectionStackingView.tsx   | 14 +++---
 src/client/views/collections/CollectionSubView.tsx |  2 +-
 .../views/collections/CollectionTimeView.tsx       |  2 +-
 .../views/collections/CollectionTreeView.tsx       |  7 +--
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 19 +++++---
 .../CollectionMulticolumnView.tsx                  |  5 +++
 .../CollectionMultirowView.tsx                     |  6 ++-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  3 +-
 .../views/nodes/ContentFittingDocumentView.tsx     | 17 ++++----
 src/client/views/nodes/DocumentView.tsx            |  4 +-
 src/client/views/nodes/FormattedTextBox.scss       |  9 ++--
 src/client/views/nodes/ImageBox.tsx                |  4 +-
 src/new_fields/util.ts                             |  2 +-
 14 files changed, 82 insertions(+), 63 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index df9f65a21..e835811c9 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -12,7 +12,7 @@ import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
 import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
 import { ComputedField } from "../../../new_fields/ScriptField";
-import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
+import { Cast, FieldValue, NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
 import { Docs, DocumentOptions } from "../../documents/Documents";
 import { Gateway } from "../../northstar/manager/Gateway";
 import { CompileScript, Transformer, ts } from "../../util/Scripting";
@@ -118,29 +118,32 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
 
     @computed
     get previewPanel() {
-        return !this.previewDocument ? (null) : <div ref={this.createTarget} style={{ width: `${this.previewWidth()}px` }}>
-            <ContentFittingDocumentView
-                Document={this.previewDocument}
-                DataDocument={undefined}
-                NativeHeight={returnZero}
-                NativeWidth={returnZero}
-                focus={emptyFunction}
-                LibraryPath={this.props.LibraryPath}
-                renderDepth={this.props.renderDepth}
-                rootSelected={this.rootSelected}
-                PanelWidth={this.previewWidth}
-                PanelHeight={this.previewHeight}
-                getTransform={this.getPreviewTransform}
-                CollectionDoc={this.props.CollectionView && this.props.CollectionView.props.Document}
-                CollectionView={this.props.CollectionView}
-                moveDocument={this.props.moveDocument}
-                addDocument={this.props.addDocument}
-                removeDocument={this.props.removeDocument}
-                active={this.props.active}
-                whenActiveChanged={this.props.whenActiveChanged}
-                addDocTab={this.props.addDocTab}
-                pinToPres={this.props.pinToPres}
-            />
+        return <div ref={this.createTarget} style={{ width: `${this.previewWidth()}px` }}>
+            {!this.previewDocument ? (null) :
+                <ContentFittingDocumentView
+                    Document={this.previewDocument}
+                    DataDocument={undefined}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
+                    fitToBox={true}
+                    FreezeDimensions={true}
+                    focus={emptyFunction}
+                    LibraryPath={this.props.LibraryPath}
+                    renderDepth={this.props.renderDepth}
+                    rootSelected={this.rootSelected}
+                    PanelWidth={this.previewWidth}
+                    PanelHeight={this.previewHeight}
+                    getTransform={this.getPreviewTransform}
+                    CollectionDoc={this.props.CollectionView?.props.Document}
+                    CollectionView={this.props.CollectionView}
+                    moveDocument={this.props.moveDocument}
+                    addDocument={this.props.addDocument}
+                    removeDocument={this.props.removeDocument}
+                    active={this.props.active}
+                    whenActiveChanged={this.props.whenActiveChanged}
+                    addDocTab={this.props.addDocTab}
+                    pinToPres={this.props.pinToPres}
+                />}
         </div>;
     }
 
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 8ceeb66f1..d17b1ee48 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -116,7 +116,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     componentDidMount() {
         super.componentDidMount();
         this._heightDisposer = reaction(() => {
-            if (this.props.Document._autoHeight && !this.props.NativeHeight()) {
+            if (this.props.Document._autoHeight && !this.layoutDoc._nativeHeight) {
                 const sectionsList = Array.from(this.Sections.size ? this.Sections.values() : [this.filteredChildren]);
                 if (this.isStackingView) {
                     const res = this.props.ContentScaling() * sectionsList.reduce((maxHght, s) => {
@@ -175,17 +175,19 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             backgroundColor={this.props.backgroundColor}
             LayoutDoc={this.props.childLayoutTemplate}
             LibraryPath={this.props.LibraryPath}
-            FreezeDimensions={this.props.freezeDimensions}
+            FreezeDimensions={this.props.freezeChildDimensions}
             renderDepth={this.props.renderDepth + 1}
-            fitToBox={this.props.fitToBox}
+            PanelWidth={width}
+            PanelHeight={height}
+            NativeHeight={returnZero}
+            NativeWidth={returnZero}
+            fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
             rootSelected={this.rootSelected}
             dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             onClick={layoutDoc.isTemplateDoc ? this.onClickHandler : this.onChildClickHandler}
-            PanelWidth={width}
-            PanelHeight={height}
             ScreenToLocalTransform={dxf}
             focus={this.props.focus}
-            ContainingCollectionDoc={this.props.CollectionView && this.props.CollectionView.props.Document}
+            ContainingCollectionDoc={this.props.CollectionView?.props.Document}
             ContainingCollectionView={this.props.CollectionView}
             addDocument={this.props.addDocument}
             moveDocument={this.props.moveDocument}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 32449de5e..a46bc67a2 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -43,7 +43,7 @@ export interface CollectionViewProps extends FieldViewProps {
 export interface SubCollectionViewProps extends CollectionViewProps {
     CollectionView: Opt<CollectionView>;
     children?: never | (() => JSX.Element[]) | React.ReactNode;
-    freezeDimensions?: boolean; // used by TimeView to coerce documents to treat their width height as their native width/height
+    freezeChildDimensions?: boolean; // used by TimeView to coerce documents to treat their width height as their native width/height
     overrideDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox)
     ignoreFields?: string[]; // used in TreeView to ignore specified fields (see LinkBox)
     isAnnotationOverlay?: boolean;
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index d9a10cdc8..4b005ba42 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -72,7 +72,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
 
     @computed get contents() {
         return <div className="collectionTimeView-innards" key="timeline" style={{ width: "100%" }}>
-            <CollectionFreeFormView {...this.props} freezeDimensions={BoolCast(this.layoutDoc._freezeChildDimensions, true)} layoutEngine={this.layoutEngine} />
+            <CollectionFreeFormView {...this.props} freezeChildDimensions={BoolCast(this.layoutDoc._freezeChildDimensions, true)} layoutEngine={this.layoutEngine} />
         </div>;
     }
 
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 10da50e35..eff4758cf 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -103,7 +103,7 @@ class TreeView extends React.Component<TreeViewProps> {
     set treeViewOpen(c: boolean) { if (this.props.treeViewPreventOpen) this._overrideTreeViewOpen = c; else this.props.document.treeViewOpen = this._overrideTreeViewOpen = c; }
     @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && BoolCast(this.props.document.treeViewOpen)) || this._overrideTreeViewOpen; }
     @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, this.defaultExpandedView); }
-    @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.document.maxEmbedHeight, 300); }
+    @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containingCollection.maxEmbedHeight, 200); }
     @computed get dataDoc() { return this.templateDataDoc ? this.templateDataDoc : this.props.document; }
     @computed get fieldKey() {
         const splits = StrCast(Doc.LayoutField(this.props.document)).split("fieldKey={\'");
@@ -280,7 +280,7 @@ class TreeView extends React.Component<TreeViewProps> {
     }
     docWidth = () => {
         const layoutDoc = Doc.Layout(this.props.document);
-        const aspect = NumCast(layoutDoc._nativeHeight) / NumCast(layoutDoc._nativeWidth);
+        const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
         if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.panelWidth() - 20));
         return NumCast(layoutDoc._nativeWidth) ? Math.min(layoutDoc[WidthSym](), this.props.panelWidth() - 20) : this.props.panelWidth() - 20;
     }
@@ -288,7 +288,7 @@ class TreeView extends React.Component<TreeViewProps> {
         const layoutDoc = Doc.Layout(this.props.document);
         const bounds = this.boundsOfCollectionDocument;
         return Math.min(this.MAX_EMBED_HEIGHT, (() => {
-            const aspect = NumCast(layoutDoc._nativeHeight) / NumCast(layoutDoc._nativeWidth, 1);
+            const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
             if (aspect) return this.docWidth() * aspect;
             if (bounds) return this.docWidth() * (bounds.b - bounds.y) / (bounds.r - bounds.x);
             return layoutDoc._fitWidth ? (!this.props.document.nativeHeight ? NumCast(this.props.containingCollection._height) :
@@ -376,6 +376,7 @@ class TreeView extends React.Component<TreeViewProps> {
                     rootSelected={returnTrue}
                     backgroundColor={this.props.backgroundColor}
                     fitToBox={this.boundsOfCollectionDocument !== undefined}
+                    FreezeDimensions={true}
                     PanelWidth={this.docWidth}
                     PanelHeight={this.docHeight}
                     getTransform={this.docTransform}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index ceec9dfcc..22dd2d831 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -15,7 +15,7 @@ import { ScriptField } from "../../../../new_fields/ScriptField";
 import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../new_fields/Types";
 import { TraceMobx } from "../../../../new_fields/util";
 import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
-import { aggregateBounds, intersectRect, returnOne, Utils } from "../../../../Utils";
+import { aggregateBounds, intersectRect, returnOne, Utils, returnZero } from "../../../../Utils";
 import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
 import { DocServer } from "../../../DocServer";
 import { Docs } from "../../../documents/Documents";
@@ -89,7 +89,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     @computed get fitToContent() { return (this.props.fitToBox || this.Document._fitToBox) && !this.isAnnotationOverlay; }
     @computed get parentScaling() { return this.props.ContentScaling && this.fitToContent && !this.isAnnotationOverlay ? this.props.ContentScaling() : 1; }
     @computed get contentBounds() { return aggregateBounds(this._layoutElements.filter(e => e.bounds && !e.bounds.z).map(e => e.bounds!), NumCast(this.layoutDoc.xPadding, 10), NumCast(this.layoutDoc.yPadding, 10)); }
-    @computed get nativeWidth() { return this.Document._fitToContent ? 0 : NumCast(this.Document._nativeWidth, this.props.NativeWidth()); }
+    @computed get nativeWidth() { return this.fitToContent ? 0 : NumCast(this.Document._nativeWidth, this.props.NativeWidth()); }
     @computed get nativeHeight() { return this.fitToContent ? 0 : NumCast(this.Document._nativeHeight, this.props.NativeHeight()); }
     private get isAnnotationOverlay() { return this.props.isAnnotationOverlay; }
     private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; }
@@ -822,10 +822,13 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps {
         return {
             ...this.props,
+            NativeHeight: returnZero,
+            NativeWidth: returnZero,
+            fitToBox: false,
             DataDoc: childData,
             Document: childLayout,
             LibraryPath: this.libraryPath,
-            FreezeDimensions: this.props.freezeDimensions,
+            FreezeDimensions: this.props.freezeChildDimensions,
             layoutKey: undefined,
             rootSelected: this.rootSelected,
             dropAction: StrCast(this.props.Document.childDropAction) as dropActionType,
@@ -958,8 +961,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                     dataProvider={this.childDataProvider}
                     LayoutDoc={this.childLayoutDocFunc}
                     jitterRotation={NumCast(this.props.Document.jitterRotation)}
-                    fitToBox={this.props.fitToBox || this.props.layoutEngine !== undefined}
-                    FreezeDimensions={this.props.layoutEngine !== undefined}
+                    fitToBox={this.props.fitToBox || BoolCast(this.props.freezeChildDimensions)}
+                    FreezeDimensions={BoolCast(this.props.freezeChildDimensions)}
                 />,
                 bounds: this.childDataProvider(pair.layout)
             }));
@@ -1122,8 +1125,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
     @computed get contentScaling() {
         if (this.props.annotationsKey) return 0;
-        const hscale = this.nativeHeight ? this.props.PanelHeight() / this.nativeHeight : 1;
-        const wscale = this.nativeWidth ? this.props.PanelWidth() / this.nativeWidth : 1;
+        const nw = NumCast(this.Document._nativeWidth, this.props.NativeWidth());
+        const nh = NumCast(this.Document._nativeHeight, this.props.NativeHeight());
+        const hscale = nh ? this.props.PanelHeight() / nh : 1;
+        const wscale = nw ? this.props.PanelWidth() / nw : 1;
         return wscale < hscale ? wscale : hscale;
     }
     render() {
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index aa8e1fb43..7e511ae34 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -14,6 +14,7 @@ import "./collectionMulticolumnView.scss";
 import ResizeBar from './MulticolumnResizer';
 import WidthLabel from './MulticolumnWidthLabel';
 import { List } from '../../../../new_fields/List';
+import { returnZero } from '../../../../Utils';
 
 type MulticolumnDocument = makeInterface<[typeof documentSchema]>;
 const MulticolumnDocument = makeInterface(documentSchema);
@@ -208,6 +209,10 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
             {...this.props}
             Document={layout}
             DataDocument={layout.resolvedDataDoc as Doc}
+            NativeHeight={returnZero}
+            NativeWidth={returnZero}
+            fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
+            FreezeDimensions={BoolCast(this.props.Document._freezeChildDimensions)}
             backgroundColor={this.props.backgroundColor}
             CollectionDoc={this.props.Document}
             PanelWidth={width}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 5e59f8237..daf1fda6c 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -6,7 +6,7 @@ import * as React from "react";
 import { Doc } from '../../../../new_fields/Doc';
 import { NumCast, StrCast, BoolCast, ScriptCast } from '../../../../new_fields/Types';
 import { ContentFittingDocumentView } from '../../nodes/ContentFittingDocumentView';
-import { Utils } from '../../../../Utils';
+import { Utils, returnZero } from '../../../../Utils';
 import "./collectionMultirowView.scss";
 import { computed, trace, observable, action } from 'mobx';
 import { Transform } from '../../../util/Transform';
@@ -208,6 +208,10 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
             {...this.props}
             Document={layout}
             DataDocument={layout.resolvedDataDoc as Doc}
+            NativeHeight={returnZero}
+            NativeWidth={returnZero}
+            fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
+            FreezeDimensions={BoolCast(this.props.Document._freezeChildDimensions)}
             backgroundColor={this.props.backgroundColor}
             CollectionDoc={this.props.Document}
             PanelWidth={width}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index e4c8bbd7b..7e9e654cd 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -10,7 +10,6 @@ import { DocumentView, DocumentViewProps } from "./DocumentView";
 import React = require("react");
 import { PositionDocument } from "../../../new_fields/documentSchemas";
 import { TraceMobx } from "../../../new_fields/util";
-import { returnFalse } from "../../../Utils";
 import { ContentFittingDocumentView } from "./ContentFittingDocumentView";
 
 export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
@@ -108,7 +107,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                     getTransform={this.getTransform}
                     NativeHeight={this.NativeHeight}
                     NativeWidth={this.NativeWidth}
-                    active={returnFalse}
+                    active={this.props.parentActive}
                     focus={this.focusDoc}
                     PanelWidth={this.panelWidth}
                     PanelHeight={this.panelHeight}
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 52e5ed1dd..f66ff8020 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -2,7 +2,7 @@ import React = require("react");
 import { computed } from "mobx";
 import { observer } from "mobx-react";
 import "react-table/react-table.css";
-import { Doc, Opt } from "../../../new_fields/Doc";
+import { Doc, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc";
 import { ScriptField } from "../../../new_fields/ScriptField";
 import { NumCast, StrCast } from "../../../new_fields/Types";
 import { TraceMobx } from "../../../new_fields/util";
@@ -15,7 +15,7 @@ import "./ContentFittingDocumentView.scss";
 import { dropActionType } from "../../util/DragManager";
 
 interface ContentFittingDocumentViewProps {
-    Document?: Doc;
+    Document: Doc;
     DataDocument?: Doc;
     LayoutDoc?: () => Opt<Doc>;
     NativeWidth?: () => number;
@@ -48,13 +48,14 @@ interface ContentFittingDocumentViewProps {
 @observer
 export class ContentFittingDocumentView extends React.Component<ContentFittingDocumentViewProps>{
     public get displayName() { return "DocumentView(" + this.props.Document?.title + ")"; } // this makes mobx trace() statements more descriptive
-    private get layoutDoc() { return this.props.Document && (this.props.LayoutDoc?.() || Doc.Layout(this.props.Document)); }
-    private nativeWidth = () => NumCast(this.layoutDoc?._nativeWidth, this.props.NativeWidth?.() || this.props.PanelWidth());
-    private nativeHeight = () => NumCast(this.layoutDoc?._nativeHeight, this.props.NativeHeight?.() || this.props.PanelHeight());
+    private get layoutDoc() { return this.props.LayoutDoc?.() || Doc.Layout(this.props.Document); }
+    @computed get freezeDimensions() { return this.props.FreezeDimensions; }
+    nativeWidth = () => { return NumCast(this.layoutDoc?._nativeWidth, this.props.NativeWidth?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[WidthSym]() : this.props.PanelWidth())); }
+    nativeHeight = () => { return NumCast(this.layoutDoc?._nativeHeight, this.props.NativeHeight?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[HeightSym]() : this.props.PanelHeight())); }
     @computed get scaling() {
-        const wscale = this.props.PanelWidth() / (this.nativeWidth() || this.props.PanelWidth() || 1);
+        const wscale = this.props.PanelWidth() / this.nativeWidth();
         if (wscale * this.nativeHeight() > this.props.PanelHeight()) {
-            return (this.props.PanelHeight() / (this.nativeHeight() || this.props.PanelHeight() || 1)) || 1;
+            return (this.props.PanelHeight() / this.nativeHeight()) || 1;
         }
         return wscale || 1;
     }
@@ -67,7 +68,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
     @computed get panelHeight() { return this.nativeHeight && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeHeight() * this.contentScaling() : this.props.PanelHeight(); }
 
     private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, -this.centeringYOffset).scale(1 / this.contentScaling());
-    private get centeringOffset() { return this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? (this.props.PanelWidth() - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
+    private get centeringOffset() { return this.nativeWidth() && !this.props.Document._fitWidth ? (this.props.PanelWidth() - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
     private get centeringYOffset() { return Math.abs(this.centeringOffset) < 0.001 ? (this.props.PanelHeight() - this.nativeHeight() * this.contentScaling()) / 2 : 0; }
 
     @computed get borderRounding() { return StrCast(this.props.Document?.borderRounding); }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index d800579a1..32c5a02e5 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -110,7 +110,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     public get displayName() { return "DocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive
     public get ContentDiv() { return this._mainCont.current; }
-    @computed get active() { return SelectionManager.IsSelected(this, true) || this.props.parentActive(true); }
+    get active() { return SelectionManager.IsSelected(this, true) || this.props.parentActive(true); }
     @computed get topMost() { return this.props.renderDepth === 0; }
     @computed get freezeDimensions() { return this.props.FreezeDimensions; }
     @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
@@ -124,8 +124,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     private _firstX: number = -1;
     private _firstY: number = -1;
 
-
-
     handle1PointerHoldStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): any => {
         this.removeMoveListeners();
         this.removeEndListeners();
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index 526939438..7d40b3149 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -39,11 +39,6 @@
         position: absolute;
     }
 }
-
-.collectionfreeformview-container {
-    position: relative;
-}
-
 .formattedTextBox-outer {
     position: relative;
     overflow: auto;
@@ -75,6 +70,10 @@
     position: absolute;
     right: 0;
 
+    .collectionfreeformview-container {
+        position: relative;
+    }
+    
     >.formattedTextBox-sidebar-handle {
         right: unset;
         left: -5;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 052251d94..e0b3a6809 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -433,12 +433,14 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
     contentFunc = () => [this.content];
     render() {
         TraceMobx();
+        const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]);
+        const aspect = (rotation % 180) ? this.Document[HeightSym]() / this.Document[WidthSym]() : 1;
         const dragging = !SelectionManager.GetIsDragging() ? "" : "-dragging";
         return (<div className={`imageBox${dragging}`} onContextMenu={this.specificContextMenu}
             style={{
                 transform: this.props.PanelWidth() ? undefined : `scale(${this.props.ContentScaling()})`,
                 width: this.props.PanelWidth() ? `${this.props.PanelWidth()}px` : `${100 / this.props.ContentScaling()}%`,
-                height: this.props.PanelWidth() ? undefined : `${100 / this.props.ContentScaling()}%`,
+                height: this.props.PanelWidth() ? `${this.props.PanelWidth() * aspect}px` : `${100 / this.props.ContentScaling()}%`,
                 pointerEvents: this.props.Document.isBackground ? "none" : undefined,
                 borderRadius: `${Number(StrCast(this.layoutDoc.borderRounding).replace("px", "")) / this.props.ContentScaling()}px`
             }} >
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 480a55da0..8c719ccd8 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -12,7 +12,7 @@ function _readOnlySetter(): never {
     throw new Error("Documents can't be modified in read-only mode");
 }
 
-const tracing = true;
+const tracing = false;
 export function TraceMobx() {
     tracing && trace();
 }
-- 
cgit v1.2.3-70-g09d2


From 11f5c3139074db379f64f7a3be98493cf18cbfd3 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 6 Apr 2020 04:07:45 -0400
Subject: everything's working with panelwidth/height etc stuff?? maybe?

---
 .../views/collections/CollectionStackingView.tsx   | 109 +++++++++++++--------
 .../CollectionStackingViewFieldColumn.tsx          |   3 +-
 .../views/collections/CollectionTreeView.tsx       |   5 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   1 +
 .../views/nodes/ContentFittingDocumentView.tsx     |  14 +--
 src/new_fields/util.ts                             |   2 +-
 6 files changed, 82 insertions(+), 52 deletions(-)

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index d17b1ee48..d9183cdb6 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -24,7 +24,7 @@ import "./CollectionStackingView.scss";
 import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn";
 import { CollectionSubView } from "./CollectionSubView";
 import { CollectionViewType } from "./CollectionView";
-import { DocumentView } from "../nodes/DocumentView";
+const _global = (window /* browser */ || global /* node */) as any;
 
 @observer
 export class CollectionStackingView extends CollectionSubView(doc => doc) {
@@ -47,6 +47,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; }
     @computed get showAddAGroup() { return (this.pivotField && (this.props.Document._chromeStatus !== 'view-mode' && this.props.Document._chromeStatus !== 'disabled')); }
     @computed get columnWidth() {
+        TraceMobx();
         return Math.min(this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin,
             this.isStackingView ? Number.MAX_VALUE : NumCast(this.props.Document.columnWidth, 250));
     }
@@ -113,34 +114,49 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         return fields;
     }
 
+    getSimpleDocHeight(d?: Doc) {
+        if (!d) return 0;
+        const layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
+        const nw = NumCast(layoutDoc._nativeWidth);
+        const nh = NumCast(layoutDoc._nativeHeight);
+        let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
+        if (!layoutDoc._fitWidth && nw && nh) {
+            const aspect = nw && nh ? nh / nw : 1;
+            if (!(this.props.Document.fillColumn)) wid = Math.min(layoutDoc[WidthSym](), wid);
+            return wid * aspect;
+        }
+        return layoutDoc._fitWidth ? wid * NumCast(layoutDoc.scrollHeight, nh) / (nw || 1) : layoutDoc[HeightSym]();
+    }
     componentDidMount() {
         super.componentDidMount();
-        this._heightDisposer = reaction(() => {
-            if (this.props.Document._autoHeight && !this.layoutDoc._nativeHeight) {
-                const sectionsList = Array.from(this.Sections.size ? this.Sections.values() : [this.filteredChildren]);
-                if (this.isStackingView) {
-                    const res = this.props.ContentScaling() * sectionsList.reduce((maxHght, s) => {
-                        const r1 = Math.max(maxHght,
-                            (this.Sections.size ? 50 : 0) + s.reduce((height, d, i) => {
-                                const val = height + this.getDocHeight(d) + (i === s.length - 1 ? this.yMargin : this.gridGap);
-                                return val;
-                            }, this.yMargin));
-                        return r1;
-                    }, 0);
-                    return res;
-                } else {
-                    const sum = Array.from(this._heightMap.values()).reduce((acc: number, curr: number) => acc += curr, 0);
-                    return this.props.ContentScaling() * (sum + (this.Sections.size ? (this.props.Document.miniHeaders ? 20 : 85) : -15));
-                }
-            }
-            return -1;
-        },
-            (hgt: number) => {
-                const doc = hgt === -1 ? undefined : this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
-                doc && hgt > 0 && (Doc.Layout(doc)._height = hgt);
-            },
-            { fireImmediately: true }
-        );
+        // this._heightDisposer = reaction(() => {
+        //     TraceMobx();
+        //     if (this.props.Document._autoHeight && !this.layoutDoc._nativeHeight) {
+        //         const sectionsList = Array.from(this.Sections.size ? this.Sections.values() : [this.filteredChildren]);
+        //         if (this.isStackingView) {
+        //             const res = Math.max(...sectionsList.map((s, i) => {
+        //                 const secSize = (this.Sections.size ? 50 : 0) + s.reduce((height, d, i) => {
+        //                     const val = this.getSimpleDocHeight(d) + (i === s.length - 1 ? this.yMargin : this.gridGap);
+        //                     console.log(d.title + " " + val + " => " + (val + height));
+        //                     return height + val;
+        //                 }, this.yMargin);
+        //                 console.log("Sec" + i + " = " + secSize);
+        //                 return secSize;
+        //             }));
+        //             return res * this.props.ContentScaling();
+        //         } else {
+        //             const sum = Array.from(this._heightMap.values()).reduce((acc: number, curr: number) => acc += curr, 0);
+        //             return this.props.ContentScaling() * (sum + (this.Sections.size ? (this.props.Document.miniHeaders ? 20 : 85) : -15));
+        //         }
+        //     }
+        //     return -1;
+        // },
+        //     (hgt: number) => {
+        //         const doc = hgt === -1 ? undefined : this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
+        //         doc && hgt > 0 && (Doc.Layout(doc)._height = hgt);
+        //     },
+        //     { fireImmediately: true }
+        // );
 
         // reset section headers when a new filter is inputted
         this._pivotFieldDisposer = reaction(
@@ -169,9 +185,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     getDisplayDoc(doc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) {
         const layoutDoc = Doc.Layout(doc, this.props.childLayoutTemplate?.());
         const height = () => this.getDocHeight(doc);
-        return <DocumentView
+        return <ContentFittingDocumentView
             Document={doc}
-            DataDoc={dataDoc || (doc[DataSym] !== doc && doc[DataSym])}
+            DataDocument={dataDoc || (doc[DataSym] !== doc && doc[DataSym])}
             backgroundColor={this.props.backgroundColor}
             LayoutDoc={this.props.childLayoutTemplate}
             LibraryPath={this.props.LibraryPath}
@@ -185,22 +201,18 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             rootSelected={this.rootSelected}
             dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             onClick={layoutDoc.isTemplateDoc ? this.onClickHandler : this.onChildClickHandler}
-            ScreenToLocalTransform={dxf}
+            getTransform={dxf}
             focus={this.props.focus}
-            ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-            ContainingCollectionView={this.props.CollectionView}
+            CollectionDoc={this.props.CollectionView?.props.Document}
+            CollectionView={this.props.CollectionView}
             addDocument={this.props.addDocument}
             moveDocument={this.props.moveDocument}
             removeDocument={this.props.removeDocument}
-            parentActive={this.props.active}
-            bringToFront={emptyFunction}
-            NativeHeight={returnZero}
-            NativeWidth={returnZero}
-            ContentScaling={returnOne}
+            active={this.props.active}
             whenActiveChanged={this.props.whenActiveChanged}
             addDocTab={this.props.addDocTab}
             pinToPres={this.props.pinToPres}>
-        </DocumentView>;
+        </ContentFittingDocumentView>;
     }
 
     getDocWidth(d?: Doc) {
@@ -295,6 +307,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         });
     }
     headings = () => Array.from(this.Sections);
+    refList = new Map<any, number>();
     sectionStacking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
         const key = this.pivotField;
         let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined;
@@ -305,6 +318,21 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         const cols = () => this.isStackingView ? 1 : Math.max(1, Math.min(this.filteredChildren.length,
             Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap))));
         return <CollectionStackingViewFieldColumn
+            observeHeight={(ref) => {
+                if (ref) {
+                    this.refList.set(ref, 0);
+                    this.observer = new _global.ResizeObserver(action((entries: any) => {
+                        if (this.props.Document.autoHeight && ref) {
+                            const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
+                            for (const entry of entries) {
+                                this.refList.set(ref, entry.contentRect.height);
+                            }
+                            Doc.Layout(doc)._height = Math.max(...Array.from(this.refList.entries()).map(entry => Number(getComputedStyle(entry[0]).height.replace("px", ""))));
+                        }
+                    }));
+                    this.observer.observe(ref);
+                }
+            }}
             key={heading ? heading.heading : ""}
             cols={cols}
             headings={this.headings}
@@ -323,11 +351,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         const y = this._scroll; // required for document decorations to update when the text box container is scrolled
         const { scale, translateX, translateY } = Utils.GetScreenTransform(dref);
         const outerXf = Utils.GetScreenTransform(this._masonryGridRef!);
-        const scaling = 1 / Math.min(1, this.props.PanelHeight() / this.layoutDoc[HeightSym]());
         const offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY);
-        const offsetx = (doc[WidthSym]() - doc[WidthSym]() / scaling) / 2;
         const offsety = (this.props.ChromeHeight && this.props.ChromeHeight() < 0 ? this.props.ChromeHeight() : 0);
-        return this.props.ScreenToLocalTransform().translate(offset[0] - offsetx, offset[1] + offsety).scale(scaling);
+        return this.props.ScreenToLocalTransform().translate(offset[0], offset[1] + offsety);
     }
 
     sectionMasonry = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
@@ -401,6 +427,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
 
     @computed get scaling() { return !this.nativeWidth ? 1 : this.props.PanelHeight() / this.nativeHeight; }
 
+    observer: any;
     render() {
         TraceMobx();
         const editableViewProps = {
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 0a48c95e4..dcaffe7af 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -39,6 +39,7 @@ interface CSVFieldColumnProps {
     type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined;
     createDropTarget: (ele: HTMLDivElement) => void;
     screenToLocalTransform: () => Transform;
+    observeHeight: (myref: any) => void;
 }
 
 @observer
@@ -358,7 +359,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
                 {this.props.parent.Document.hideHeadings ? (null) : headingView}
                 {
                     this.collapsed ? (null) :
-                        <div>
+                        <div ref={ref => ref && this.props.observeHeight(ref)}>
                             <div key={`${heading}-stack`} className={`collectionStackingView-masonry${singleColumn ? "Single" : "Grid"}`}
                                 style={{
                                     padding: singleColumn ? `${columnYMargin}px ${0}px ${style.yMargin}px ${0}px` : `${columnYMargin}px ${0}px`,
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index eff4758cf..7edda5a4f 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -267,8 +267,9 @@ class TreeView extends React.Component<TreeViewProps> {
     docTransform = () => {
         const { scale, translateX, translateY } = Utils.GetScreenTransform(this._dref.current!);
         const outerXf = this.props.outerXf();
-        const offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY);
-        const finalXf = this.props.ScreenToLocalTransform().translate(offset[0], offset[1] + (this.props.ChromeHeight && this.props.ChromeHeight() < 0 ? this.props.ChromeHeight() : 0));
+        const offset = this.props.ScreenToLocalTransform().transformDirection((outerXf.translateX - translateX), outerXf.translateY - translateY);
+        const finalXf = this.props.ScreenToLocalTransform().translate(offset[0], offset[1]);
+
         return finalXf;
     }
     getTransform = () => {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 22dd2d831..9581ec255 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -99,6 +99,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     private zoomScaling = () => (1 / this.parentScaling) * (this.fitToContent ?
         Math.min(this.props.PanelHeight() / (this.contentBounds.b - this.contentBounds.y), this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x)) :
         this.Document.scale || 1)
+
     private centeringShiftX = () => !this.nativeWidth && !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling : 0;  // shift so pan position is at center of window for non-overlay collections
     private centeringShiftY = () => !this.nativeHeight && !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling : 0;// shift so pan position is at center of window for non-overlay collections
     private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth + 1, -this.borderWidth + 1).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform());
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index f66ff8020..642264b85 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -50,8 +50,8 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
     public get displayName() { return "DocumentView(" + this.props.Document?.title + ")"; } // this makes mobx trace() statements more descriptive
     private get layoutDoc() { return this.props.LayoutDoc?.() || Doc.Layout(this.props.Document); }
     @computed get freezeDimensions() { return this.props.FreezeDimensions; }
-    nativeWidth = () => { return NumCast(this.layoutDoc?._nativeWidth, this.props.NativeWidth?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[WidthSym]() : this.props.PanelWidth())); }
-    nativeHeight = () => { return NumCast(this.layoutDoc?._nativeHeight, this.props.NativeHeight?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[HeightSym]() : this.props.PanelHeight())); }
+    nativeWidth = () => NumCast(this.layoutDoc?._nativeWidth, this.props.NativeWidth?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[WidthSym]() : this.props.PanelWidth()));
+    nativeHeight = () => NumCast(this.layoutDoc?._nativeHeight, this.props.NativeHeight?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[HeightSym]() : this.props.PanelHeight()));
     @computed get scaling() {
         const wscale = this.props.PanelWidth() / this.nativeWidth();
         if (wscale * this.nativeHeight() > this.props.PanelHeight()) {
@@ -64,8 +64,8 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
     private PanelWidth = () => this.panelWidth;
     private PanelHeight = () => this.panelHeight;
 
-    @computed get panelWidth() { return this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeWidth() * this.contentScaling() : this.props.PanelWidth(); }
-    @computed get panelHeight() { return this.nativeHeight && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeHeight() * this.contentScaling() : this.props.PanelHeight(); }
+    @computed get panelWidth() { return this.nativeWidth && !this.props.Document._fitWidth ? this.nativeWidth() * this.contentScaling() : this.props.PanelWidth(); }
+    @computed get panelHeight() { return this.nativeHeight && !this.props.Document._fitWidth ? this.nativeHeight() * this.contentScaling() : this.props.PanelHeight(); }
 
     private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, -this.centeringYOffset).scale(1 / this.contentScaling());
     private get centeringOffset() { return this.nativeWidth() && !this.props.Document._fitWidth ? (this.props.PanelWidth() - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
@@ -94,6 +94,9 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         LibraryPath={this.props.LibraryPath}
                         NativeWidth={this.nativeWidth}
                         NativeHeight={this.nativeHeight}
+                        PanelWidth={this.PanelWidth}
+                        PanelHeight={this.PanelHeight}
+                        ContentScaling={this.contentScaling}
                         fitToBox={this.props.fitToBox}
                         layoutKey={this.props.layoutKey}
                         dropAction={this.props.dropAction}
@@ -110,9 +113,6 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         parentActive={this.props.active}
                         ScreenToLocalTransform={this.getTransform}
                         renderDepth={this.props.renderDepth}
-                        ContentScaling={this.contentScaling}
-                        PanelWidth={this.PanelWidth}
-                        PanelHeight={this.PanelHeight}
                         focus={this.props.focus || emptyFunction}
                         bringToFront={emptyFunction}
                         dontRegisterView={this.props.dontRegisterView}
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 8c719ccd8..480a55da0 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -12,7 +12,7 @@ function _readOnlySetter(): never {
     throw new Error("Documents can't be modified in read-only mode");
 }
 
-const tracing = false;
+const tracing = true;
 export function TraceMobx() {
     tracing && trace();
 }
-- 
cgit v1.2.3-70-g09d2


From 155f44b563c1338422de5f8f9a7429c69da1039d Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 6 Apr 2020 13:14:57 -0400
Subject: fixed sizing stacking views.  fixed rotating images.  fixed undo
 stacking drags.

---
 src/client/util/DragManager.ts                     |  7 +++-
 .../views/collections/CollectionStackingView.scss  |  3 ++
 .../views/collections/CollectionStackingView.tsx   | 45 ++++------------------
 .../CollectionStackingViewFieldColumn.tsx          | 16 +++++++-
 src/client/views/nodes/ImageBox.tsx                | 14 ++++---
 src/new_fields/util.ts                             |  2 +-
 6 files changed, 40 insertions(+), 47 deletions(-)

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

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 1f2312032..53c0a2963 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -17,6 +17,7 @@ import { convertDropDataToButtons } from "./DropConverter";
 import { AudioBox } from "../views/nodes/AudioBox";
 import { DateField } from "../../new_fields/DateField";
 import { DocumentView } from "../views/nodes/DocumentView";
+import { UndoManager } from "./UndoManager";
 
 export type dropActionType = "place" | "alias" | "copy" | undefined;
 export function SetupDrag(
@@ -199,6 +200,7 @@ export namespace DragManager {
             dropDoc instanceof Doc && AudioBox.ActiveRecordings.map(d => DocUtils.MakeLink({ doc: dropDoc }, { doc: d }, "audio link", "audio timeline"));
             return dropDoc;
         };
+        const batch = UndoManager.StartBatch("dragging");
         const finishDrag = (e: DragCompleteEvent) => {
             e.docDragData && (e.docDragData.droppedDocuments =
                 dragData.draggedDocuments.map(d => !dragData.isSelectionMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) :
@@ -208,6 +210,7 @@ export namespace DragManager {
             e.docDragData?.droppedDocuments.forEach((drop: Doc, i: number) =>
                 (dragData?.removeDropProperties || []).concat(Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec("string"), [])).map(prop => drop[prop] = undefined)
             );
+            batch.end();
         };
         dragData.draggedDocuments.map(d => d.dragFactory); // does this help?  trying to make sure the dragFactory Doc is loaded
         StartDrag(eles, dragData, downX, downY, options, finishDrag);
@@ -401,15 +404,17 @@ export namespace DragManager {
 
     function dispatchDrag(dragEles: HTMLElement[], e: PointerEvent, dragData: { [index: string]: any }, options?: DragOptions, finishDrag?: (e: DragCompleteEvent) => void) {
         const removed = dragData.dontHideOnDrop ? [] : dragEles.map(dragEle => {
-            const ret = { ele: dragEle, w: dragEle.style.width, h: dragEle.style.height };
+            const ret = { ele: dragEle, w: dragEle.style.width, h: dragEle.style.height, o: dragEle.style.overflow };
             dragEle.style.width = "0";
             dragEle.style.height = "0";
+            dragEle.style.overflow = "hidden";
             return ret;
         });
         const target = document.elementFromPoint(e.x, e.y);
         removed.map(r => {
             r.ele.style.width = r.w;
             r.ele.style.height = r.h;
+            r.ele.style.overflow = r.o;
         });
         if (target) {
             const complete = new DragCompleteEvent(false, dragData);
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index bfa5ea278..47faa9239 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -26,6 +26,9 @@
         position: relative;
         display: block;
     }
+    .collectionStackingViewFieldColumn {
+        height:max-content;
+    }
 
     .collectionSchemaView-previewDoc {
         height: 100%;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index d9183cdb6..84e6ecced 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -24,13 +24,13 @@ import "./CollectionStackingView.scss";
 import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn";
 import { CollectionSubView } from "./CollectionSubView";
 import { CollectionViewType } from "./CollectionView";
+import { SelectionManager } from "../../util/SelectionManager";
 const _global = (window /* browser */ || global /* node */) as any;
 
 @observer
 export class CollectionStackingView extends CollectionSubView(doc => doc) {
     _masonryGridRef: HTMLDivElement | null = null;
     _draggerRef = React.createRef<HTMLDivElement>();
-    _heightDisposer?: IReactionDisposer;
     _pivotFieldDisposer?: IReactionDisposer;
     _docXfs: any[] = [];
     _columnStart: number = 0;
@@ -129,34 +129,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
     componentDidMount() {
         super.componentDidMount();
-        // this._heightDisposer = reaction(() => {
-        //     TraceMobx();
-        //     if (this.props.Document._autoHeight && !this.layoutDoc._nativeHeight) {
-        //         const sectionsList = Array.from(this.Sections.size ? this.Sections.values() : [this.filteredChildren]);
-        //         if (this.isStackingView) {
-        //             const res = Math.max(...sectionsList.map((s, i) => {
-        //                 const secSize = (this.Sections.size ? 50 : 0) + s.reduce((height, d, i) => {
-        //                     const val = this.getSimpleDocHeight(d) + (i === s.length - 1 ? this.yMargin : this.gridGap);
-        //                     console.log(d.title + " " + val + " => " + (val + height));
-        //                     return height + val;
-        //                 }, this.yMargin);
-        //                 console.log("Sec" + i + " = " + secSize);
-        //                 return secSize;
-        //             }));
-        //             return res * this.props.ContentScaling();
-        //         } else {
-        //             const sum = Array.from(this._heightMap.values()).reduce((acc: number, curr: number) => acc += curr, 0);
-        //             return this.props.ContentScaling() * (sum + (this.Sections.size ? (this.props.Document.miniHeaders ? 20 : 85) : -15));
-        //         }
-        //     }
-        //     return -1;
-        // },
-        //     (hgt: number) => {
-        //         const doc = hgt === -1 ? undefined : this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
-        //         doc && hgt > 0 && (Doc.Layout(doc)._height = hgt);
-        //     },
-        //     { fireImmediately: true }
-        // );
 
         // reset section headers when a new filter is inputted
         this._pivotFieldDisposer = reaction(
@@ -166,7 +138,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
     componentWillUnmount() {
         super.componentWillUnmount();
-        this._heightDisposer?.();
         this._pivotFieldDisposer?.();
     }
 
@@ -307,7 +278,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         });
     }
     headings = () => Array.from(this.Sections);
-    refList = new Map<any, number>();
+    refList: any[] = [];
     sectionStacking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
         const key = this.pivotField;
         let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined;
@@ -318,16 +289,14 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         const cols = () => this.isStackingView ? 1 : Math.max(1, Math.min(this.filteredChildren.length,
             Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap))));
         return <CollectionStackingViewFieldColumn
+            unobserveHeight={(ref) => this.refList.splice(this.refList.indexOf(ref), 1)}
             observeHeight={(ref) => {
                 if (ref) {
-                    this.refList.set(ref, 0);
+                    this.refList.push(ref);
+                    const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
                     this.observer = new _global.ResizeObserver(action((entries: any) => {
-                        if (this.props.Document.autoHeight && ref) {
-                            const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
-                            for (const entry of entries) {
-                                this.refList.set(ref, entry.contentRect.height);
-                            }
-                            Doc.Layout(doc)._height = Math.max(...Array.from(this.refList.entries()).map(entry => Number(getComputedStyle(entry[0]).height.replace("px", ""))));
+                        if (this.props.Document._autoHeight && ref && !SelectionManager.GetIsDragging()) {
+                            Doc.Layout(doc)._height = Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", ""))));
                         }
                     }));
                     this.observer.observe(ref);
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index dcaffe7af..5d926b7c7 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -40,6 +40,7 @@ interface CSVFieldColumnProps {
     createDropTarget: (ele: HTMLDivElement) => void;
     screenToLocalTransform: () => Transform;
     observeHeight: (myref: any) => void;
+    unobserveHeight: (myref: any) => void;
 }
 
 @observer
@@ -51,13 +52,19 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
 
     @observable _heading = this.props.headingObject ? this.props.headingObject.heading : this.props.heading;
     @observable _color = this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
+    _ele: HTMLElement | null = null;
 
     createColumnDropRef = (ele: HTMLDivElement | null) => {
         this.dropDisposer?.();
         if (ele) {
+            this._ele = ele;
+            this.props.observeHeight(ele);
             this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this));
         }
     }
+    componentWillUnmount() {
+        this.props.unobserveHeight(this._ele);
+    }
 
     @undoBatch
     columnDrop = action((e: Event, de: DragManager.DropEvent) => {
@@ -354,12 +361,17 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth / style.numGroupColumns}px `;
         const chromeStatus = this.props.parent.props.Document._chromeStatus;
         return (
-            <div className="collectionStackingViewFieldColumn" key={heading} style={{ width: `${100 / ((uniqueHeadings.length + ((chromeStatus !== 'view-mode' && chromeStatus !== 'disabled') ? 1 : 0)) || 1)}%`, background: this._background }}
+            <div className="collectionStackingViewFieldColumn" key={heading}
+                style={{
+                    width: `${100 / ((uniqueHeadings.length + ((chromeStatus !== 'view-mode' && chromeStatus !== 'disabled') ? 1 : 0)) || 1)}%`,
+                    height: SelectionManager.GetIsDragging() ? "100%" : undefined,
+                    background: this._background
+                }}
                 ref={this.createColumnDropRef} onPointerEnter={this.pointerEntered} onPointerLeave={this.pointerLeave}>
                 {this.props.parent.Document.hideHeadings ? (null) : headingView}
                 {
                     this.collapsed ? (null) :
-                        <div ref={ref => ref && this.props.observeHeight(ref)}>
+                        <div>
                             <div key={`${heading}-stack`} className={`collectionStackingView-masonry${singleColumn ? "Single" : "Grid"}`}
                                 style={{
                                     padding: singleColumn ? `${columnYMargin}px ${0}px ${style.yMargin}px ${0}px` : `${columnYMargin}px ${0}px`,
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index e0b3a6809..4a1b71a9e 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -392,8 +392,12 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
         const fadepath = this.paths[Math.min(1, this.paths.length - 1)];
         const { nativeWidth, nativeHeight } = this.nativeSize;
         const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]);
-        const aspect = (rotation % 180) ? this.Document[HeightSym]() / this.Document[WidthSym]() : 1;
-        const shift = (rotation % 180) ? (nativeHeight - nativeWidth / aspect) / 2 : 0;
+        const aspect = (rotation % 180) ? nativeHeight / nativeWidth : 1;
+        //const shift = (rotation % 180) ? -(nativeHeight - nativeHeight * aspect) : 0;
+        const pwidth = this.props.PanelWidth();
+        const pheight = this.props.PanelHeight();
+        const shift = (rotation % 180) ? (pheight - pwidth) / aspect / 2 + (pheight - pwidth) / 2 : 0;
+        //(300 - 168) / 1.7778 / 2  + (300 - 168)/2
 
         this.resize(srcpath);
 
@@ -433,14 +437,14 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
     contentFunc = () => [this.content];
     render() {
         TraceMobx();
-        const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]);
-        const aspect = (rotation % 180) ? this.Document[HeightSym]() / this.Document[WidthSym]() : 1;
+        const { nativeWidth, nativeHeight } = this.nativeSize;
+        const aspect = nativeWidth / nativeHeight;
         const dragging = !SelectionManager.GetIsDragging() ? "" : "-dragging";
         return (<div className={`imageBox${dragging}`} onContextMenu={this.specificContextMenu}
             style={{
                 transform: this.props.PanelWidth() ? undefined : `scale(${this.props.ContentScaling()})`,
                 width: this.props.PanelWidth() ? `${this.props.PanelWidth()}px` : `${100 / this.props.ContentScaling()}%`,
-                height: this.props.PanelWidth() ? `${this.props.PanelWidth() * aspect}px` : `${100 / this.props.ContentScaling()}%`,
+                height: this.props.PanelWidth() ? `${this.props.PanelWidth() / aspect}px` : `${100 / this.props.ContentScaling()}%`,
                 pointerEvents: this.props.Document.isBackground ? "none" : undefined,
                 borderRadius: `${Number(StrCast(this.layoutDoc.borderRounding).replace("px", "")) / this.props.ContentScaling()}px`
             }} >
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 480a55da0..8c719ccd8 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -12,7 +12,7 @@ function _readOnlySetter(): never {
     throw new Error("Documents can't be modified in read-only mode");
 }
 
-const tracing = true;
+const tracing = false;
 export function TraceMobx() {
     tracing && trace();
 }
-- 
cgit v1.2.3-70-g09d2


From 490584f292e1da100bbb26ea3be1d06b5f63232d Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 6 Apr 2020 14:04:39 -0400
Subject: fixed autoHeight for masonry & removing observers when switching out

---
 .../collections/CollectionMasonryViewFieldRow.tsx    | 12 ++++++++++--
 .../views/collections/CollectionStackingView.tsx     | 20 +++++++++++++++++---
 2 files changed, 27 insertions(+), 5 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index af3e18a4b..b272151c1 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -36,6 +36,9 @@ interface CMVFieldRowProps {
     createDropTarget: (ele: HTMLDivElement) => void;
     screenToLocalTransform: () => Transform;
     setDocHeight: (key: string, thisHeight: number) => void;
+    observeHeight: (myref: any) => void;
+    unobserveHeight: (myref: any) => void;
+    showHandle: boolean;
 }
 
 @observer
@@ -53,14 +56,19 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     private _contRef: React.RefObject<HTMLDivElement> = React.createRef();
     private _sensitivity: number = 16;
     private _counter: number = 0;
-
+    private _ele: any;
 
     createRowDropRef = (ele: HTMLDivElement | null) => {
         this._dropDisposer && this._dropDisposer();
         if (ele) {
+            this._ele = ele;
+            this.props.observeHeight(ele);
             this._dropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this));
         }
     }
+    componentWillUnmount() {
+        this.props.unobserveHeight(this._ele);
+    }
 
     getTrueHeight = () => {
         if (this._collapsed) {
@@ -293,7 +301,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
                         gridTemplateColumns: numberRange(rows).reduce((list: string, i: any) => list + ` ${this.props.parent.columnWidth}px`, ""),
                     }}>
                     {this.props.parent.children(this.props.docList)}
-                    {this.props.parent.columnDragger}
+                    {this.props.showHandle && this.props.parent.props.active() ? this.props.parent.columnDragger : (null)}
                 </div>
             </div>;
     }
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 84e6ecced..b066f2be3 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -295,7 +295,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                     this.refList.push(ref);
                     const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
                     this.observer = new _global.ResizeObserver(action((entries: any) => {
-                        if (this.props.Document._autoHeight && ref && !SelectionManager.GetIsDragging()) {
+                        if (this.props.Document._autoHeight && ref && this.refList.length && !SelectionManager.GetIsDragging()) {
                             Doc.Layout(doc)._height = Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", ""))));
                         }
                     }));
@@ -325,7 +325,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         return this.props.ScreenToLocalTransform().translate(offset[0], offset[1] + offsety);
     }
 
-    sectionMasonry = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
+    sectionMasonry = (heading: SchemaHeaderField | undefined, docList: Doc[], first: boolean) => {
         const key = this.pivotField;
         let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined;
         const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]);
@@ -335,6 +335,20 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         const rows = () => !this.isStackingView ? 1 : Math.max(1, Math.min(docList.length,
             Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap))));
         return <CollectionMasonryViewFieldRow
+            showHandle={first}
+            unobserveHeight={(ref) => this.refList.splice(this.refList.indexOf(ref), 1)}
+            observeHeight={(ref) => {
+                if (ref) {
+                    this.refList.push(ref);
+                    const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
+                    this.observer = new _global.ResizeObserver(action((entries: any) => {
+                        if (this.props.Document._autoHeight && ref && this.refList.length && !SelectionManager.GetIsDragging()) {
+                            Doc.Layout(doc)._height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0)
+                        }
+                    }));
+                    this.observer.observe(ref);
+                }
+            }}
             key={heading ? heading.heading : ""}
             rows={rows}
             headings={this.headings}
@@ -387,7 +401,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             const entries = Array.from(this.Sections.entries());
             sections = entries.sort(this.sortFunc);
         }
-        return sections.map(section => this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1]));
+        return sections.map((section, i) => this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1], i === 0));
     }
 
 
-- 
cgit v1.2.3-70-g09d2


From e262d9ac73af5b2cef384468c47d69917e205d44 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 7 Apr 2020 23:01:46 -0400
Subject: lots of code cleanup - removed all northstar db stuff.  added
 scriptingBox.  renamed things.  made collectiontypes strings not numbers.

---
 package-lock.json                                  |    8 +-
 .../apis/google_docs/GoogleApiClientUtils.ts       |    2 +-
 src/client/apis/youtube/YoutubeBox.tsx             |    6 +-
 src/client/documents/DocumentTypes.ts              |   61 +-
 src/client/documents/Documents.ts                  |  108 +-
 src/client/northstar/core/BaseObject.ts            |   12 -
 .../northstar/core/attribute/AttributeModel.ts     |  111 -
 .../core/attribute/AttributeTransformationModel.ts |   52 -
 .../core/attribute/CalculatedAttributeModel.ts     |   42 -
 .../northstar/core/brusher/IBaseBrushable.ts       |   13 -
 src/client/northstar/core/brusher/IBaseBrusher.ts  |   11 -
 src/client/northstar/core/filter/FilterModel.ts    |   83 -
 src/client/northstar/core/filter/FilterOperand.ts  |    5 -
 src/client/northstar/core/filter/FilterType.ts     |    6 -
 .../northstar/core/filter/IBaseFilterConsumer.ts   |   12 -
 .../northstar/core/filter/IBaseFilterProvider.ts   |    8 -
 .../northstar/core/filter/ValueComparision.ts      |   78 -
 src/client/northstar/dash-fields/HistogramField.ts |   66 -
 .../dash-nodes/HistogramBinPrimitiveCollection.ts  |  240 -
 src/client/northstar/dash-nodes/HistogramBox.scss  |   40 -
 src/client/northstar/dash-nodes/HistogramBox.tsx   |  175 -
 .../dash-nodes/HistogramBoxPrimitives.scss         |   42 -
 .../dash-nodes/HistogramBoxPrimitives.tsx          |  122 -
 .../dash-nodes/HistogramLabelPrimitives.scss       |   13 -
 .../dash-nodes/HistogramLabelPrimitives.tsx        |   80 -
 src/client/northstar/manager/Gateway.ts            |  299 -
 src/client/northstar/model/ModelExtensions.ts      |   48 -
 src/client/northstar/model/ModelHelpers.ts         |  220 -
 .../model/binRanges/AlphabeticVisualBinRange.ts    |   52 -
 .../model/binRanges/DateTimeVisualBinRange.ts      |  105 -
 .../model/binRanges/NominalVisualBinRange.ts       |   52 -
 .../model/binRanges/QuantitativeVisualBinRange.ts  |   90 -
 .../northstar/model/binRanges/VisualBinRange.ts    |   32 -
 .../model/binRanges/VisualBinRangeHelper.ts        |   70 -
 .../northstar/model/idea/MetricTypeMapping.ts      |   30 -
 src/client/northstar/model/idea/idea.ts            | 8557 --------------------
 src/client/northstar/operations/BaseOperation.ts   |  162 -
 .../northstar/operations/HistogramOperation.ts     |  158 -
 src/client/northstar/utils/ArrayUtil.ts            |   90 -
 src/client/northstar/utils/Extensions.ts           |   29 -
 src/client/northstar/utils/GeometryUtil.ts         |  133 -
 src/client/northstar/utils/IDisposable.ts          |    3 -
 src/client/northstar/utils/IEquatable.ts           |    3 -
 src/client/northstar/utils/KeyCodes.ts             |  137 -
 src/client/northstar/utils/LABColor.ts             |   90 -
 src/client/northstar/utils/MathUtil.ts             |  249 -
 src/client/northstar/utils/PartialClass.ts         |    7 -
 src/client/northstar/utils/SizeConverter.ts        |  101 -
 src/client/northstar/utils/StyleContants.ts        |   95 -
 src/client/northstar/utils/Utils.ts                |   75 -
 src/client/util/DictationManager.ts                |    6 +-
 src/client/util/DropConverter.ts                   |    2 +-
 src/client/util/KeyCodes.ts                        |  136 +
 src/client/util/type_decls.d                       |    1 -
 src/client/views/DocComponent.tsx                  |    2 +-
 src/client/views/DocumentDecorations.tsx           |    2 +-
 src/client/views/MainView.tsx                      |    6 +-
 src/client/views/ScriptBox.tsx                     |    2 +-
 src/client/views/SearchDocBox.tsx                  |    2 +-
 .../views/collections/CollectionSchemaCells.tsx    |    5 +-
 .../views/collections/CollectionSchemaView.tsx     |   22 -
 .../views/collections/CollectionStackingView.tsx   |    2 +-
 src/client/views/collections/CollectionSubView.tsx |    2 +-
 src/client/views/collections/CollectionView.tsx    |   52 +-
 .../views/collections/CollectionViewChromes.tsx    |    7 +-
 .../views/collections/ParentDocumentSelector.tsx   |    2 +-
 .../CollectionFreeFormLinkView.tsx                 |   10 +-
 .../CollectionFreeFormLinksView.tsx                |   56 -
 src/client/views/nodes/AudioBox.scss               |    4 +-
 src/client/views/nodes/ButtonBox.scss              |   38 -
 src/client/views/nodes/ButtonBox.tsx               |   97 -
 src/client/views/nodes/DocuLinkBox.scss            |   29 -
 src/client/views/nodes/DocuLinkBox.tsx             |  146 -
 src/client/views/nodes/DocumentBox.tsx             |    8 +-
 src/client/views/nodes/DocumentContentsView.tsx    |   14 +-
 src/client/views/nodes/DocumentView.scss           |    4 +-
 src/client/views/nodes/DocumentView.tsx            |   40 +-
 src/client/views/nodes/FormattedTextBox.tsx        |    4 +-
 src/client/views/nodes/LabelBox.scss               |   38 +
 src/client/views/nodes/LabelBox.tsx                |   97 +
 src/client/views/nodes/LinkAnchorBox.scss          |   29 +
 src/client/views/nodes/LinkAnchorBox.tsx           |  146 +
 src/client/views/nodes/PDFBox.tsx                  |    3 +-
 src/client/views/nodes/PresBox.tsx                 |   10 +-
 src/client/views/nodes/ScriptingBox.scss           |    0
 src/client/views/nodes/ScriptingBox.tsx            |   71 +
 src/client/views/nodes/VideoBox.tsx                |    2 +-
 src/client/views/pdf/PDFViewer.tsx                 |    2 +-
 src/client/views/search/FilterBox.tsx              |    2 +-
 src/client/views/search/IconBar.tsx                |    2 +-
 src/client/views/search/IconButton.tsx             |    8 +-
 src/client/views/search/SearchBox.tsx              |    2 +-
 src/client/views/search/SearchItem.tsx             |    9 +-
 src/new_fields/Doc.ts                              |    6 +-
 src/new_fields/RichTextField.ts                    |    3 -
 src/new_fields/ScriptField.ts                      |    5 +-
 src/new_fields/documentSchemas.ts                  |    2 +-
 src/server/Message.ts                              |    2 +-
 src/server/RouteManager.ts                         |    1 -
 src/server/Websocket/Websocket.ts                  |    3 +-
 .../authentication/models/current_user_utils.ts    |   73 -
 src/server/updateProtos.ts                         |    3 +-
 102 files changed, 695 insertions(+), 12808 deletions(-)
 delete mode 100644 src/client/northstar/core/BaseObject.ts
 delete mode 100644 src/client/northstar/core/attribute/AttributeModel.ts
 delete mode 100644 src/client/northstar/core/attribute/AttributeTransformationModel.ts
 delete mode 100644 src/client/northstar/core/attribute/CalculatedAttributeModel.ts
 delete mode 100644 src/client/northstar/core/brusher/IBaseBrushable.ts
 delete mode 100644 src/client/northstar/core/brusher/IBaseBrusher.ts
 delete mode 100644 src/client/northstar/core/filter/FilterModel.ts
 delete mode 100644 src/client/northstar/core/filter/FilterOperand.ts
 delete mode 100644 src/client/northstar/core/filter/FilterType.ts
 delete mode 100644 src/client/northstar/core/filter/IBaseFilterConsumer.ts
 delete mode 100644 src/client/northstar/core/filter/IBaseFilterProvider.ts
 delete mode 100644 src/client/northstar/core/filter/ValueComparision.ts
 delete mode 100644 src/client/northstar/dash-fields/HistogramField.ts
 delete mode 100644 src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts
 delete mode 100644 src/client/northstar/dash-nodes/HistogramBox.scss
 delete mode 100644 src/client/northstar/dash-nodes/HistogramBox.tsx
 delete mode 100644 src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss
 delete mode 100644 src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
 delete mode 100644 src/client/northstar/dash-nodes/HistogramLabelPrimitives.scss
 delete mode 100644 src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx
 delete mode 100644 src/client/northstar/manager/Gateway.ts
 delete mode 100644 src/client/northstar/model/ModelExtensions.ts
 delete mode 100644 src/client/northstar/model/ModelHelpers.ts
 delete mode 100644 src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts
 delete mode 100644 src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts
 delete mode 100644 src/client/northstar/model/binRanges/NominalVisualBinRange.ts
 delete mode 100644 src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts
 delete mode 100644 src/client/northstar/model/binRanges/VisualBinRange.ts
 delete mode 100644 src/client/northstar/model/binRanges/VisualBinRangeHelper.ts
 delete mode 100644 src/client/northstar/model/idea/MetricTypeMapping.ts
 delete mode 100644 src/client/northstar/model/idea/idea.ts
 delete mode 100644 src/client/northstar/operations/BaseOperation.ts
 delete mode 100644 src/client/northstar/operations/HistogramOperation.ts
 delete mode 100644 src/client/northstar/utils/ArrayUtil.ts
 delete mode 100644 src/client/northstar/utils/Extensions.ts
 delete mode 100644 src/client/northstar/utils/GeometryUtil.ts
 delete mode 100644 src/client/northstar/utils/IDisposable.ts
 delete mode 100644 src/client/northstar/utils/IEquatable.ts
 delete mode 100644 src/client/northstar/utils/KeyCodes.ts
 delete mode 100644 src/client/northstar/utils/LABColor.ts
 delete mode 100644 src/client/northstar/utils/MathUtil.ts
 delete mode 100644 src/client/northstar/utils/PartialClass.ts
 delete mode 100644 src/client/northstar/utils/SizeConverter.ts
 delete mode 100644 src/client/northstar/utils/StyleContants.ts
 delete mode 100644 src/client/northstar/utils/Utils.ts
 create mode 100644 src/client/util/KeyCodes.ts
 delete mode 100644 src/client/views/nodes/ButtonBox.scss
 delete mode 100644 src/client/views/nodes/ButtonBox.tsx
 delete mode 100644 src/client/views/nodes/DocuLinkBox.scss
 delete mode 100644 src/client/views/nodes/DocuLinkBox.tsx
 create mode 100644 src/client/views/nodes/LabelBox.scss
 create mode 100644 src/client/views/nodes/LabelBox.tsx
 create mode 100644 src/client/views/nodes/LinkAnchorBox.scss
 create mode 100644 src/client/views/nodes/LinkAnchorBox.tsx
 create mode 100644 src/client/views/nodes/ScriptingBox.scss
 create mode 100644 src/client/views/nodes/ScriptingBox.tsx

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

diff --git a/package-lock.json b/package-lock.json
index 2cd3c0b82..1949a8a5c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -750,7 +750,7 @@
         },
         "@types/passport": {
             "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.2.tgz",
+            "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.0.tgz",
             "integrity": "sha512-Pf39AYKf8q+YoONym3150cEwfUD66dtwHJWvbeOzKxnA0GZZ/vAXhNWv9vMhKyRQBQZiQyWQnhYBEBlKW6G8wg==",
             "requires": {
                 "@types/express": "*"
@@ -14376,7 +14376,7 @@
         },
         "readable-stream": {
             "version": "2.3.6",
-            "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
             "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
             "requires": {
                 "core-util-is": "~1.0.0",
@@ -15990,7 +15990,7 @@
         },
         "strip-ansi": {
             "version": "3.0.1",
-            "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
             "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
             "requires": {
                 "ansi-regex": "^2.0.0"
@@ -18303,7 +18303,7 @@
         },
         "wrap-ansi": {
             "version": "2.1.0",
-            "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+            "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
             "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
             "requires": {
                 "string-width": "^1.0.1",
diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts
index 0d44ee8e0..fa67ddbef 100644
--- a/src/client/apis/google_docs/GoogleApiClientUtils.ts
+++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts
@@ -97,7 +97,7 @@ export namespace GoogleApiClientUtils {
                 const paragraphs = extractParagraphs(document);
                 let text = paragraphs.map(paragraph => paragraph.contents.filter(content => !("inlineObjectId" in content)).map(run => run as docs_v1.Schema$TextRun).join("")).join("");
                 text = text.substring(0, text.length - 1);
-                removeNewlines && text.ReplaceAll("\n", "");
+                removeNewlines && text.replace(/\n/g, "");
                 return { text, paragraphs };
             };
 
diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index c940bba43..4b4145fcc 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -171,9 +171,9 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
      * in the title of the videos.
      */
     filterYoutubeTitleResult = (resultTitle: string) => {
-        let processedTitle: string = resultTitle.ReplaceAll("&amp;", "&");
-        processedTitle = processedTitle.ReplaceAll("&#39;", "'");
-        processedTitle = processedTitle.ReplaceAll("&quot;", "\"");
+        let processedTitle: string = resultTitle.replace(/&amp;/g, "&");//.ReplaceAll("&amp;", "&");
+        processedTitle = processedTitle.replace(/"&#39;/g, "'");
+        processedTitle = processedTitle.replace(/&quot;/g, "\"");
         return processedTitle;
     }
 
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index b6a6cc75a..ab32d7301 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -1,31 +1,36 @@
 export enum DocumentType {
     NONE = "none",
-    TEXT = "text",
-    HIST = "histogram",
-    IMG = "image",
-    WEB = "web",
-    COL = "collection",
-    KVP = "kvp",
-    VID = "video",
-    AUDIO = "audio",
-    PDF = "pdf",
-    IMPORT = "import",
-    LINK = "link",
-    LINKDB = "linkdb",
-    BUTTON = "button",
-    SLIDER = "slider",
-    YOUTUBE = "youtube",
-    WEBCAM = "webcam",
-    FONTICON = "fonticonbox",
-    PRES = "presentation",
-    RECOMMENDATION = "recommendation",
-    LINKFOLLOW = "linkfollow",
-    PRESELEMENT = "preselement",
-    QUERY = "query",
-    COLOR = "color",
-    DOCULINK = "doculink",
-    PDFANNO = "pdfanno",
-    INK = "ink",
-    DOCUMENT = "document",
-    SCREENSHOT = "screenshot",
+
+    // core data types
+    RTF = "rtf",      // rich text
+    IMG = "image",      // image box
+    WEB = "web",        // web page or html clipping
+    COL = "collection", // collection
+    KVP = "kvp",        // key value pane
+    VID = "video",      // video
+    AUDIO = "audio",    // audio
+    PDF = "pdf",        // pdf
+    INK = "ink",        // ink stroke
+    SCREENSHOT = "screenshot",  // view of a desktop application
+    FONTICON = "fonticonbox",   // font icon
+    QUERY = "query",            // search query
+    LABEL = "label",            // simple text label
+    WEBCAM = "webcam",          // webcam
+    PDFANNO = "pdfanno",        // pdf text selection (could be just a collection?)
+    DATE = "date",              // calendar view of a date
+    SCRIPTING = "script",       // script editor
+
+    // special purpose wrappers that either take no data or are compositions of lower level types
+    LINK = "link",              // link  (view of a document that acts as a link)
+    LINKANCHOR = "linkanchor",  // blue dot link anchor  (view of a link document's anchor)
+    IMPORT = "import",          // directory import box  (file system directory)
+    SLIDER = "slider",          // number slider  (view of a number)
+    PRES = "presentation",      // presentation   (view of a collection) --- shouldn't this be a view type?  technically requires a special view in which documents must have their aliasOf fields filled in
+    PRESELEMENT = "preselement",// presentation item (view of a document in a collection)
+    COLOR = "color",            // color picker (view of a color picker for a color string)
+    YOUTUBE = "youtube",        // youtube directory (view of you tube search results)
+    DOCHOLDER = "docholder",    // nested document (view of a document)
+
+    LINKDB = "linkdb",          // database of links  ??? why do we have this
+    RECOMMENDATION = "recommendation", // view of a recommendation
 }
\ No newline at end of file
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index cca0e7bc6..b71205001 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1,6 +1,3 @@
-import { HistogramField } from "../northstar/dash-fields/HistogramField";
-import { HistogramBox } from "../northstar/dash-nodes/HistogramBox";
-import { HistogramOperation } from "../northstar/operations/HistogramOperation";
 import { CollectionView } from "../views/collections/CollectionView";
 import { CollectionViewType } from "../views/collections/CollectionView";
 import { AudioBox } from "../views/nodes/AudioBox";
@@ -8,21 +5,16 @@ import { FormattedTextBox } from "../views/nodes/FormattedTextBox";
 import { ImageBox } from "../views/nodes/ImageBox";
 import { KeyValueBox } from "../views/nodes/KeyValueBox";
 import { PDFBox } from "../views/nodes/PDFBox";
+import { ScriptingBox } from "../views/nodes/ScriptingBox";
 import { VideoBox } from "../views/nodes/VideoBox";
 import { WebBox } from "../views/nodes/WebBox";
-import { Gateway } from "../northstar/manager/Gateway";
 import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
-import { action } from "mobx";
-import { ColumnAttributeModel } from "../northstar/core/attribute/AttributeModel";
-import { AttributeTransformationModel } from "../northstar/core/attribute/AttributeTransformationModel";
-import { AggregateFunction } from "../northstar/model/idea/idea";
 import { OmitKeys, JSONUtils, Utils } from "../../Utils";
 import { Field, Doc, Opt, DocListCastAsync, FieldResult, DocListCast } from "../../new_fields/Doc";
 import { ImageField, VideoField, AudioField, PdfField, WebField, YoutubeField } from "../../new_fields/URLField";
 import { HtmlField } from "../../new_fields/HtmlField";
 import { List } from "../../new_fields/List";
 import { Cast, NumCast, StrCast } from "../../new_fields/Types";
-import { listSpec } from "../../new_fields/Schema";
 import { DocServer } from "../DocServer";
 import { dropActionType } from "../util/DragManager";
 import { DateField } from "../../new_fields/DateField";
@@ -32,7 +24,7 @@ import { LinkManager } from "../util/LinkManager";
 import { DocumentManager } from "../util/DocumentManager";
 import DirectoryImportBox from "../util/Import & Export/DirectoryImportBox";
 import { Scripting } from "../util/Scripting";
-import { ButtonBox } from "../views/nodes/ButtonBox";
+import { LabelBox } from "../views/nodes/LabelBox";
 import { SliderBox } from "../views/nodes/SliderBox";
 import { FontIconBox } from "../views/nodes/FontIconBox";
 import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField";
@@ -41,16 +33,12 @@ import { ComputedField, ScriptField } from "../../new_fields/ScriptField";
 import { ProxyField } from "../../new_fields/Proxy";
 import { DocumentType } from "./DocumentTypes";
 import { RecommendationsBox } from "../views/RecommendationsBox";
-import { SearchBox } from "../views/search/SearchBox";
-
-//import { PresBox } from "../views/nodes/PresBox";
-//import { PresField } from "../../new_fields/PresField";
 import { PresElementBox } from "../views/presentationview/PresElementBox";
 import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
 import { QueryBox } from "../views/nodes/QueryBox";
 import { ColorBox } from "../views/nodes/ColorBox";
-import { DocuLinkBox } from "../views/nodes/DocuLinkBox";
-import { DocumentBox } from "../views/nodes/DocumentBox";
+import { LinkAnchorBox } from "../views/nodes/LinkAnchorBox";
+import { DocHolderBox } from "../views/nodes/DocumentBox";
 import { InkingStroke } from "../views/InkingStroke";
 import { InkField } from "../../new_fields/InkField";
 import { InkingControl } from "../views/InkingControl";
@@ -80,7 +68,7 @@ export interface DocumentOptions {
     _showCaption?: string; // which field to display in the caption area.  leave empty to have no caption
     _scrollTop?: number; // scroll location for pdfs
     _chromeStatus?: string;
-    _viewType?: number;
+    _viewType?: string; // sub type of a collection
     _gridGap?: number; // gap between items in masonry view
     _xMargin?: number; // gap between left edge of document and start of masonry/stacking layouts
     _yMargin?: number; // gap between top edge of dcoument and start of masonry/stacking layouts
@@ -156,6 +144,7 @@ export interface DocumentOptions {
     treeViewChecked?: ScriptField; // script to call when a tree view checkbox is checked
     isFacetFilter?: boolean; // whether document functions as a facet filter in a tree view
     limitHeight?: number; // maximum height for newly created (eg, from pasting) text documents
+    editScriptOnClick?: string; // script field key to edit when document is clicked (e.g., "onClick", "onChecked")
     // [key: string]: Opt<Field>;
     pointerHack?: boolean; // for buttons, allows onClick handler to fire onPointerDown
     textTransform?: string; // is linear view expanded
@@ -192,14 +181,10 @@ export namespace Docs {
         const data = "data";
 
         const TemplateMap: TemplateMap = new Map([
-            [DocumentType.TEXT, {
+            [DocumentType.RTF, {
                 layout: { view: FormattedTextBox, dataField: "text" },
                 options: { _height: 150, _xMargin: 10, _yMargin: 10 }
             }],
-            [DocumentType.HIST, {
-                layout: { view: HistogramBox, dataField: data },
-                options: { _height: 300, backgroundColor: "black" }
-            }],
             [DocumentType.QUERY, {
                 layout: { view: QueryBox, dataField: data },
                 options: { _width: 400 }
@@ -224,8 +209,8 @@ export namespace Docs {
                 layout: { view: KeyValueBox, dataField: data },
                 options: { _height: 150 }
             }],
-            [DocumentType.DOCUMENT, {
-                layout: { view: DocumentBox, dataField: data },
+            [DocumentType.DOCHOLDER, {
+                layout: { view: DocHolderBox, dataField: data },
                 options: { _height: 250 }
             }],
             [DocumentType.VID, {
@@ -253,11 +238,14 @@ export namespace Docs {
                 layout: { view: EmptyBox, dataField: data },
                 options: { childDropAction: "alias", title: "LINK DB" }
             }],
+            [DocumentType.SCRIPTING, {
+                layout: { view: ScriptingBox, dataField: data }
+            }],
             [DocumentType.YOUTUBE, {
                 layout: { view: YoutubeBox, dataField: data }
             }],
-            [DocumentType.BUTTON, {
-                layout: { view: ButtonBox, dataField: data },
+            [DocumentType.LABEL, {
+                layout: { view: LabelBox, dataField: data },
             }],
             [DocumentType.SLIDER, {
                 layout: { view: SliderBox, dataField: data },
@@ -521,6 +509,10 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.PRES), initial, options);
         }
 
+        export function ScriptingDocument(url: string, options: DocumentOptions = {}) {
+            return InstanceFromProto(Prototypes.get(DocumentType.SCRIPTING), new YoutubeField(new URL(url)), options);
+        }
+
         export function VideoDocument(url: string, options: DocumentOptions = {}) {
             return InstanceFromProto(Prototypes.get(DocumentType.VID), new VideoField(new URL(url)), options);
         }
@@ -543,10 +535,6 @@ export namespace Docs {
             return instance;
         }
 
-        export function HistogramDocument(histoOp: HistogramOperation, options: DocumentOptions = {}) {
-            return InstanceFromProto(Prototypes.get(DocumentType.HIST), new HistogramField(histoOp), options);
-        }
-
         export function QueryDocument(options: DocumentOptions = {}) {
             return InstanceFromProto(Prototypes.get(DocumentType.QUERY), "", options);
         }
@@ -556,7 +544,7 @@ export namespace Docs {
         }
 
         export function TextDocument(text: string, options: DocumentOptions = {}) {
-            return InstanceFromProto(Prototypes.get(DocumentType.TEXT), text, options, undefined, "text");
+            return InstanceFromProto(Prototypes.get(DocumentType.RTF), text, options, undefined, "text");
         }
 
         export function LinkDocument(source: { doc: Doc, ctx?: Doc }, target: { doc: Doc, ctx?: Doc }, options: DocumentOptions = {}, id?: string) {
@@ -566,8 +554,8 @@ export namespace Docs {
             linkDocProto.anchor2 = target.doc;
 
             if (linkDocProto.layout_key1 === undefined) {
-                Cast(linkDocProto.proto, Doc, null).layout_key1 = DocuLinkBox.LayoutString("anchor1");
-                Cast(linkDocProto.proto, Doc, null).layout_key2 = DocuLinkBox.LayoutString("anchor2");
+                Cast(linkDocProto.proto, Doc, null).layout_key1 = LinkAnchorBox.LayoutString("anchor1");
+                Cast(linkDocProto.proto, Doc, null).layout_key2 = LinkAnchorBox.LayoutString("anchor2");
                 Cast(linkDocProto.proto, Doc, null).linkBoxExcludedKeys = new List(["treeViewExpandedView", "treeViewHideTitle", "removeDropProperties", "linkBoxExcludedKeys", "treeViewOpen", "aliasNumber", "isPrototype", "lastOpened", "creationDate", "author"]);
                 Cast(linkDocProto.proto, Doc, null).layoutKey = undefined;
             }
@@ -605,37 +593,6 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.PDF), new PdfField(new URL(url)), options);
         }
 
-        export async function DBDocument(url: string, options: DocumentOptions = {}, columnOptions: DocumentOptions = {}) {
-            const schemaName = options.title ? options.title : "-no schema-";
-            const ctlog = await Gateway.Instance.GetSchema(url, schemaName);
-            if (ctlog && ctlog.schemas) {
-                const schema = ctlog.schemas[0];
-                const schemaDoc = Docs.Create.TreeDocument([], { ...options, _nativeWidth: undefined, _nativeHeight: undefined, _width: 150, _height: 100, title: schema.displayName! });
-                const schemaDocuments = Cast(schemaDoc.data, listSpec(Doc), []);
-                if (!schemaDocuments) {
-                    return;
-                }
-                CurrentUserUtils.AddNorthstarSchema(schema, schemaDoc);
-                const docs = schemaDocuments;
-                CurrentUserUtils.GetAllNorthstarColumnAttributes(schema).map(attr => {
-                    DocServer.GetRefField(attr.displayName! + ".alias").then(action((field: Opt<Field>) => {
-                        if (field instanceof Doc) {
-                            docs.push(field);
-                        } else {
-                            const atmod = new ColumnAttributeModel(attr);
-                            const histoOp = new HistogramOperation(schema.displayName!,
-                                new AttributeTransformationModel(atmod, AggregateFunction.None),
-                                new AttributeTransformationModel(atmod, AggregateFunction.Count),
-                                new AttributeTransformationModel(atmod, AggregateFunction.Count));
-                            docs.push(Docs.Create.HistogramDocument(histoOp, { ...columnOptions, _width: 200, _height: 200, title: attr.displayName! }));
-                        }
-                    }));
-                });
-                return schemaDoc;
-            }
-            return Docs.Create.TreeDocument([], { _width: 50, _height: 100, title: schemaName });
-        }
-
         export function WebDocument(url: string, options: DocumentOptions = {}) {
             return InstanceFromProto(Prototypes.get(DocumentType.WEB), new WebField(new URL(url)), options);
         }
@@ -649,7 +606,7 @@ export namespace Docs {
         }
 
         export function DocumentDocument(document?: Doc, options: DocumentOptions = {}) {
-            return InstanceFromProto(Prototypes.get(DocumentType.DOCUMENT), document, { title: document ? document.title + "" : "container", ...options });
+            return InstanceFromProto(Prototypes.get(DocumentType.DOCHOLDER), document, { title: document ? document.title + "" : "container", ...options });
         }
 
         export function FreeformDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
@@ -688,8 +645,12 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Masonry });
         }
 
+        export function LabelDocument(options?: DocumentOptions) {
+            return InstanceFromProto(Prototypes.get(DocumentType.LABEL), undefined, { ...(options || {}) });
+        }
+
         export function ButtonDocument(options?: DocumentOptions) {
-            return InstanceFromProto(Prototypes.get(DocumentType.BUTTON), undefined, { ...(options || {}) });
+            return InstanceFromProto(Prototypes.get(DocumentType.LABEL), undefined, { ...(options || {}), editScriptOnClick: "onClick" });
         }
 
         export function SliderDocument(options?: DocumentOptions) {
@@ -842,9 +803,6 @@ export namespace Docs {
             } else if (field instanceof AudioField) {
                 created = Docs.Create.AudioDocument((field).url.href, resolved);
                 layout = AudioBox.LayoutString;
-            } else if (field instanceof HistogramField) {
-                created = Docs.Create.HistogramDocument((field).HistoOp, resolved);
-                layout = HistogramBox.LayoutString;
             } else if (field instanceof InkField) {
                 const { selectedColor, selectedWidth, selectedTool } = InkingControl.Instance;
                 created = Docs.Create.InkDocument(selectedColor, selectedTool, Number(selectedWidth), (field).inkData, resolved);
@@ -856,9 +814,11 @@ export namespace Docs {
                 created = Docs.Create.TextDocument("", { ...{ _width: 200, _height: 25, _autoHeight: true }, ...resolved });
                 layout = FormattedTextBox.LayoutString;
             }
-            created.layout = layout?.(fieldKey);
-            created.title = fieldKey;
-            proto && (created.proto = Doc.GetProto(proto));
+            if (created) {
+                created.layout = layout?.(fieldKey);
+                created.title = fieldKey;
+                proto && created.proto && (created.proto = Doc.GetProto(proto));
+            }
             return created;
         }
 
@@ -881,10 +841,6 @@ export namespace Docs {
                 if (!options._width) options._width = 400;
                 if (!options._height) options._height = options._width * 1200 / 927;
             }
-            if (type.indexOf("excel") !== -1) {
-                ctor = Docs.Create.DBDocument;
-                options.dropAction = "copy";
-            }
             if (type.indexOf("html") !== -1) {
                 if (path.includes(window.location.hostname)) {
                     const s = path.split('/');
diff --git a/src/client/northstar/core/BaseObject.ts b/src/client/northstar/core/BaseObject.ts
deleted file mode 100644
index ed3818071..000000000
--- a/src/client/northstar/core/BaseObject.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { IEquatable } from '../utils/IEquatable';
-import { IDisposable } from '../utils/IDisposable';
-
-export class BaseObject implements IEquatable, IDisposable {
-
-    public Equals(other: Object): boolean {
-        return this === other;
-    }
-
-    public Dispose(): void {
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/core/attribute/AttributeModel.ts b/src/client/northstar/core/attribute/AttributeModel.ts
deleted file mode 100644
index c89b1617c..000000000
--- a/src/client/northstar/core/attribute/AttributeModel.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-import { Attribute, DataType, VisualizationHint } from '../../model/idea/idea';
-import { BaseObject } from '../BaseObject';
-import { observable } from "mobx";
-
-export abstract class AttributeModel extends BaseObject {
-    public abstract get DisplayName(): string;
-    public abstract get CodeName(): string;
-    public abstract get DataType(): DataType;
-    public abstract get VisualizationHints(): VisualizationHint[];
-}
-
-export class ColumnAttributeModel extends AttributeModel {
-    public Attribute: Attribute;
-
-    constructor(attribute: Attribute) {
-        super();
-        this.Attribute = attribute;
-    }
-
-    public get DataType(): DataType {
-        return this.Attribute.dataType ? this.Attribute.dataType : DataType.Undefined;
-    }
-
-    public get DisplayName(): string {
-        return this.Attribute.displayName ? this.Attribute.displayName.ReplaceAll("_", " ") : "";
-    }
-
-    public get CodeName(): string {
-        return this.Attribute.rawName ? this.Attribute.rawName : "";
-    }
-
-    public get VisualizationHints(): VisualizationHint[] {
-        return this.Attribute.visualizationHints ? this.Attribute.visualizationHints : [];
-    }
-
-    public Equals(other: ColumnAttributeModel): boolean {
-        return this.Attribute.rawName === other.Attribute.rawName;
-    }
-}
-
-export class CodeAttributeModel extends AttributeModel {
-    private _visualizationHints: VisualizationHint[];
-
-    public CodeName: string;
-
-    @observable
-    public Code: string;
-
-    constructor(code: string, codeName: string, displayName: string, visualizationHints: VisualizationHint[]) {
-        super();
-        this.Code = code;
-        this.CodeName = codeName;
-        this.DisplayName = displayName;
-        this._visualizationHints = visualizationHints;
-    }
-
-    public get DataType(): DataType {
-        return DataType.Undefined;
-    }
-
-    @observable
-    public DisplayName: string;
-
-    public get VisualizationHints(): VisualizationHint[] {
-        return this._visualizationHints;
-    }
-
-    public Equals(other: CodeAttributeModel): boolean {
-        return this.CodeName === other.CodeName;
-    }
-
-}
-
-export class BackendAttributeModel extends AttributeModel {
-    private _dataType: DataType;
-    private _displayName: string;
-    private _codeName: string;
-    private _visualizationHints: VisualizationHint[];
-
-    public Id: string;
-
-    constructor(id: string, dataType: DataType, displayName: string, codeName: string, visualizationHints: VisualizationHint[]) {
-        super();
-        this.Id = id;
-        this._dataType = dataType;
-        this._displayName = displayName;
-        this._codeName = codeName;
-        this._visualizationHints = visualizationHints;
-    }
-
-    public get DataType(): DataType {
-        return this._dataType;
-    }
-
-    public get DisplayName(): string {
-        return this._displayName.ReplaceAll("_", " ");
-    }
-
-    public get CodeName(): string {
-        return this._codeName;
-    }
-
-    public get VisualizationHints(): VisualizationHint[] {
-        return this._visualizationHints;
-    }
-
-    public Equals(other: BackendAttributeModel): boolean {
-        return this.Id === other.Id;
-    }
-
-}
\ No newline at end of file
diff --git a/src/client/northstar/core/attribute/AttributeTransformationModel.ts b/src/client/northstar/core/attribute/AttributeTransformationModel.ts
deleted file mode 100644
index 66485183b..000000000
--- a/src/client/northstar/core/attribute/AttributeTransformationModel.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-
-import { computed, observable } from "mobx";
-import { AggregateFunction } from "../../model/idea/idea";
-import { AttributeModel } from "./AttributeModel";
-import { IEquatable } from "../../utils/IEquatable";
-
-export class AttributeTransformationModel implements IEquatable {
-
-    @observable public AggregateFunction: AggregateFunction;
-    @observable public AttributeModel: AttributeModel;
-
-    constructor(attributeModel: AttributeModel, aggregateFunction: AggregateFunction = AggregateFunction.None) {
-        this.AttributeModel = attributeModel;
-        this.AggregateFunction = aggregateFunction;
-    }
-
-    @computed
-    public get PresentedName(): string {
-        var displayName = this.AttributeModel.DisplayName;
-        if (this.AggregateFunction === AggregateFunction.Count) {
-            return "count";
-        }
-        if (this.AggregateFunction === AggregateFunction.Avg) {
-            displayName = "avg(" + displayName + ")";
-        }
-        else if (this.AggregateFunction === AggregateFunction.Max) {
-            displayName = "max(" + displayName + ")";
- }
-        else if (this.AggregateFunction === AggregateFunction.Min) {
-            displayName = "min(" + displayName + ")";
- }
-        else if (this.AggregateFunction === AggregateFunction.Sum) {
-            displayName = "sum(" + displayName + ")";
- }
-        else if (this.AggregateFunction === AggregateFunction.SumE) {
-            displayName = "sumE(" + displayName + ")";
- }
-
-        return displayName;
-    }
-
-    public clone(): AttributeTransformationModel {
-        var clone = new AttributeTransformationModel(this.AttributeModel);
-        clone.AggregateFunction = this.AggregateFunction;
-        return clone;
-    }
-
-    public Equals(other: AttributeTransformationModel): boolean {
-        return this.AggregateFunction === other.AggregateFunction &&
-            this.AttributeModel.Equals(other.AttributeModel);
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/core/attribute/CalculatedAttributeModel.ts b/src/client/northstar/core/attribute/CalculatedAttributeModel.ts
deleted file mode 100644
index a197c1305..000000000
--- a/src/client/northstar/core/attribute/CalculatedAttributeModel.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { BackendAttributeModel, AttributeModel, CodeAttributeModel } from "./AttributeModel";
-import { DataType, VisualizationHint } from '../../model/idea/idea';
-
-export class CalculatedAttributeManager {
-    public static AllCalculatedAttributes: Array<AttributeModel> = new Array<AttributeModel>();
-
-    public static Clear() {
-        this.AllCalculatedAttributes = new Array<AttributeModel>();
-    }
-
-    public static CreateBackendAttributeModel(id: string, dataType: DataType, displayName: string, codeName: string, visualizationHints: VisualizationHint[]): BackendAttributeModel {
-        var filtered = this.AllCalculatedAttributes.filter(am => {
-            if (am instanceof BackendAttributeModel &&
-                am.Id === id) {
-                return true;
-            }
-            return false;
-        });
-        if (filtered.length > 0) {
-            return filtered[0] as BackendAttributeModel;
-        }
-        var newAttr = new BackendAttributeModel(id, dataType, displayName, codeName, visualizationHints);
-        this.AllCalculatedAttributes.push(newAttr);
-        return newAttr;
-    }
-
-    public static CreateCodeAttributeModel(code: string, codeName: string, visualizationHints: VisualizationHint[]): CodeAttributeModel {
-        var filtered = this.AllCalculatedAttributes.filter(am => {
-            if (am instanceof CodeAttributeModel &&
-                am.CodeName === codeName) {
-                return true;
-            }
-            return false;
-        });
-        if (filtered.length > 0) {
-            return filtered[0] as CodeAttributeModel;
-        }
-        var newAttr = new CodeAttributeModel(code, codeName, codeName.ReplaceAll("_", " "), visualizationHints);
-        this.AllCalculatedAttributes.push(newAttr);
-        return newAttr;
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/core/brusher/IBaseBrushable.ts b/src/client/northstar/core/brusher/IBaseBrushable.ts
deleted file mode 100644
index 87f4ba413..000000000
--- a/src/client/northstar/core/brusher/IBaseBrushable.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { PIXIPoint } from '../../utils/MathUtil';
-import { IEquatable } from '../../utils/IEquatable';
-import { Doc } from '../../../../new_fields/Doc';
-
-export interface IBaseBrushable<T> extends IEquatable {
-    BrusherModels: Array<Doc>;
-    BrushColors: Array<number>;
-    Position: PIXIPoint;
-    Size: PIXIPoint;
-}
-export function instanceOfIBaseBrushable<T>(object: any): object is IBaseBrushable<T> {
-    return 'BrusherModels' in object;
-}
\ No newline at end of file
diff --git a/src/client/northstar/core/brusher/IBaseBrusher.ts b/src/client/northstar/core/brusher/IBaseBrusher.ts
deleted file mode 100644
index d2de6ed62..000000000
--- a/src/client/northstar/core/brusher/IBaseBrusher.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { PIXIPoint } from '../../utils/MathUtil';
-import { IEquatable } from '../../utils/IEquatable';
-
-
-export interface IBaseBrusher<T> extends IEquatable {
-    Position: PIXIPoint;
-    Size: PIXIPoint;
-}
-export function instanceOfIBaseBrusher<T>(object: any): object is IBaseBrusher<T> {
-    return 'BrushableModels' in object;
-}
\ No newline at end of file
diff --git a/src/client/northstar/core/filter/FilterModel.ts b/src/client/northstar/core/filter/FilterModel.ts
deleted file mode 100644
index 6ab96b33d..000000000
--- a/src/client/northstar/core/filter/FilterModel.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-import { ValueComparison } from "./ValueComparision";
-import { Utils } from "../../utils/Utils";
-import { IBaseFilterProvider } from "./IBaseFilterProvider";
-import { FilterOperand } from "./FilterOperand";
-import { HistogramField } from "../../dash-fields/HistogramField";
-import { Cast, FieldValue } from "../../../../new_fields/Types";
-import { Doc } from "../../../../new_fields/Doc";
-
-export class FilterModel {
-    public ValueComparisons: ValueComparison[];
-    constructor() {
-        this.ValueComparisons = new Array<ValueComparison>();
-    }
-
-    public Equals(other: FilterModel): boolean {
-        if (!Utils.EqualityHelper(this, other)) return false;
-        if (!this.isSame(this.ValueComparisons, (other).ValueComparisons)) return false;
-        return true;
-    }
-
-    private isSame(a: ValueComparison[], b: ValueComparison[]): boolean {
-        if (a.length !== b.length) {
-            return false;
-        }
-        for (let i = 0; i < a.length; i++) {
-            let valueComp = a[i];
-            if (!valueComp.Equals(b[i])) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    public ToPythonString(): string {
-        return "(" + this.ValueComparisons.map(vc => vc.ToPythonString()).join("&&") + ")";
-    }
-
-    public static And(filters: string[]): string {
-        let ret = filters.filter(f => f !== "").join(" && ");
-        return ret;
-    }
-    public static GetFilterModelsRecursive(baseOperation: IBaseFilterProvider, visitedFilterProviders: Set<IBaseFilterProvider>, filterModels: FilterModel[], isFirst: boolean): string {
-        let ret = "";
-        visitedFilterProviders.add(baseOperation);
-        let filtered = baseOperation.FilterModels.filter(fm => fm && fm.ValueComparisons.length > 0);
-        if (!isFirst && filtered.length > 0) {
-            filterModels.push(...filtered);
-            ret = "(" + baseOperation.FilterModels.filter(fm => fm !== null).map(fm => fm.ToPythonString()).join(" || ") + ")";
-        }
-        if (Utils.isBaseFilterConsumer(baseOperation) && baseOperation.Links) {
-            let children = new Array<string>();
-            let linkedGraphNodes = baseOperation.Links;
-            linkedGraphNodes.map(linkVm => {
-                let filterDoc = FieldValue(Cast(linkVm.linkedFrom, Doc));
-                if (filterDoc) {
-                    let filterHistogram = Cast(filterDoc.data, HistogramField);
-                    if (filterHistogram) {
-                        if (!visitedFilterProviders.has(filterHistogram.HistoOp)) {
-                            let child = FilterModel.GetFilterModelsRecursive(filterHistogram.HistoOp, visitedFilterProviders, filterModels, false);
-                            if (child !== "") {
-                                // if (linkVm.IsInverted) {
-                                //     child = "! " + child;
-                                // }
-                                children.push(child);
-                            }
-                        }
-                    }
-                }
-            });
-
-            let childrenJoined = children.join(baseOperation.FilterOperand === FilterOperand.AND ? " && " : " || ");
-            if (children.length > 0) {
-                if (ret !== "") {
-                    ret = "(" + ret + " &&  (" + childrenJoined + "))";
-                }
-                else {
-                    ret = "(" + childrenJoined + ")";
-                }
-            }
-        }
-        return ret;
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/core/filter/FilterOperand.ts b/src/client/northstar/core/filter/FilterOperand.ts
deleted file mode 100644
index 2e8e8d6a0..000000000
--- a/src/client/northstar/core/filter/FilterOperand.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export enum FilterOperand
-{
-    AND,
-    OR
-}
\ No newline at end of file
diff --git a/src/client/northstar/core/filter/FilterType.ts b/src/client/northstar/core/filter/FilterType.ts
deleted file mode 100644
index 9adbc087f..000000000
--- a/src/client/northstar/core/filter/FilterType.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export enum FilterType
-{
-    Filter,
-    Brush,
-    Slice
-}
\ No newline at end of file
diff --git a/src/client/northstar/core/filter/IBaseFilterConsumer.ts b/src/client/northstar/core/filter/IBaseFilterConsumer.ts
deleted file mode 100644
index e7549d113..000000000
--- a/src/client/northstar/core/filter/IBaseFilterConsumer.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { FilterOperand } from '../filter/FilterOperand';
-import { IEquatable } from '../../utils/IEquatable';
-import { Doc } from '../../../../new_fields/Doc';
-
-export interface IBaseFilterConsumer extends IEquatable {
-    FilterOperand: FilterOperand;
-    Links: Doc[];
-}
-
-export function instanceOfIBaseFilterConsumer(object: any): object is IBaseFilterConsumer {
-    return 'FilterOperand' in object;
-}
\ No newline at end of file
diff --git a/src/client/northstar/core/filter/IBaseFilterProvider.ts b/src/client/northstar/core/filter/IBaseFilterProvider.ts
deleted file mode 100644
index fc3301b11..000000000
--- a/src/client/northstar/core/filter/IBaseFilterProvider.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { FilterModel } from '../filter/FilterModel';
-
-export interface IBaseFilterProvider {
-    FilterModels: Array<FilterModel>;
-}
-export function instanceOfIBaseFilterProvider(object: any): object is IBaseFilterProvider {
-    return 'FilterModels' in object;
-}
\ No newline at end of file
diff --git a/src/client/northstar/core/filter/ValueComparision.ts b/src/client/northstar/core/filter/ValueComparision.ts
deleted file mode 100644
index 65687a82b..000000000
--- a/src/client/northstar/core/filter/ValueComparision.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-import { Predicate } from '../../model/idea/idea';
-import { Utils } from '../../utils/Utils';
-import { AttributeModel } from '../attribute/AttributeModel';
-
-export class ValueComparison {
-
-    public attributeModel: AttributeModel;
-    public Value: any;
-    public Predicate: Predicate;
-
-    public constructor(attributeModel: AttributeModel, predicate: Predicate, value: any) {
-        this.attributeModel = attributeModel;
-        this.Value = value;
-        this.Predicate = predicate;
-    }
-
-    public Equals(other: Object): boolean {
-        if (!Utils.EqualityHelper(this, other)) {
-            return false;
-        }
-        if (this.Predicate !== (other as ValueComparison).Predicate) {
-            return false;
-        }
-        let isComplex = (typeof this.Value === "object");
-        if (!isComplex && this.Value !== (other as ValueComparison).Value) {
-            return false;
-        }
-        if (isComplex && !this.Value.Equals((other as ValueComparison).Value)) {
-            return false;
-        }
-        return true;
-    }
-
-    public ToPythonString(): string {
-        var op = "";
-        switch (this.Predicate) {
-            case Predicate.EQUALS:
-                op = "==";
-                break;
-            case Predicate.GREATER_THAN:
-                op = ">";
-                break;
-            case Predicate.GREATER_THAN_EQUAL:
-                op = ">=";
-                break;
-            case Predicate.LESS_THAN:
-                op = "<";
-                break;
-            case Predicate.LESS_THAN_EQUAL:
-                op = "<=";
-                break;
-            default:
-                op = "==";
-                break;
-        }
-
-        var val = this.Value.toString();
-        if (typeof this.Value === 'string' || this.Value instanceof String) {
-            val = "\"" + val + "\"";
-        }
-        var ret = " ";
-        var rawName = this.attributeModel.CodeName;
-        switch (this.Predicate) {
-            case Predicate.STARTS_WITH:
-                ret += rawName + " != null && " + rawName + ".StartsWith(" + val + ") ";
-                return ret;
-            case Predicate.ENDS_WITH:
-                ret += rawName + " != null && " + rawName + ".EndsWith(" + val + ") ";
-                return ret;
-            case Predicate.CONTAINS:
-                ret += rawName + " != null && " + rawName + ".Contains(" + val + ") ";
-                return ret;
-            default:
-                ret += rawName + " " + op + " " + val + " ";
-                return ret;
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts
deleted file mode 100644
index 076516977..000000000
--- a/src/client/northstar/dash-fields/HistogramField.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import { observable } from "mobx";
-import { custom, serializable } from "serializr";
-import { ColumnAttributeModel } from "../../../client/northstar/core/attribute/AttributeModel";
-import { AttributeTransformationModel } from "../../../client/northstar/core/attribute/AttributeTransformationModel";
-import { HistogramOperation } from "../../../client/northstar/operations/HistogramOperation";
-import { ObjectField } from "../../../new_fields/ObjectField";
-import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
-import { OmitKeys } from "../../../Utils";
-import { Deserializable } from "../../util/SerializationHelper";
-import { Copy, ToScriptString, ToString } from "../../../new_fields/FieldSymbols";
-
-function serialize(field: HistogramField) {
-    const obj = OmitKeys(field, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit;
-    return obj;
-}
-
-function deserialize(jp: any) {
-    let X: AttributeTransformationModel | undefined;
-    let Y: AttributeTransformationModel | undefined;
-    let V: AttributeTransformationModel | undefined;
-
-    const schema = CurrentUserUtils.GetNorthstarSchema(jp.SchemaName);
-    if (schema) {
-        CurrentUserUtils.GetAllNorthstarColumnAttributes(schema).map(attr => {
-            if (attr.displayName === jp.X.AttributeModel.Attribute.DisplayName) {
-                X = new AttributeTransformationModel(new ColumnAttributeModel(attr), jp.X.AggregateFunction);
-            }
-            if (attr.displayName === jp.Y.AttributeModel.Attribute.DisplayName) {
-                Y = new AttributeTransformationModel(new ColumnAttributeModel(attr), jp.Y.AggregateFunction);
-            }
-            if (attr.displayName === jp.V.AttributeModel.Attribute.DisplayName) {
-                V = new AttributeTransformationModel(new ColumnAttributeModel(attr), jp.V.AggregateFunction);
-            }
-        });
-        if (X && Y && V) {
-            return new HistogramOperation(jp.SchemaName, X, Y, V, jp.Normalization);
-        }
-    }
-    return HistogramOperation.Empty;
-}
-
-@Deserializable("histogramField")
-export class HistogramField extends ObjectField {
-    @serializable(custom(serialize, deserialize)) @observable public readonly HistoOp: HistogramOperation;
-    constructor(data?: HistogramOperation) {
-        super();
-        this.HistoOp = data ? data : HistogramOperation.Empty;
-    }
-
-    toString(): string {
-        return JSON.stringify(OmitKeys(this.HistoOp, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit);
-    }
-
-    [Copy]() {
-        // const y = this.HistoOp;
-        // const z = this.HistoOp.Copy;
-        return new HistogramField(HistogramOperation.Duplicate(this.HistoOp));
-    }
-
-    [ToScriptString]() {
-        return this.toString();
-    }
-    [ToString]() {
-        return this.toString();
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts b/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts
deleted file mode 100644
index 6b36ffc9e..000000000
--- a/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts
+++ /dev/null
@@ -1,240 +0,0 @@
-import React = require("react");
-import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel";
-import { ChartType } from '../../northstar/model/binRanges/VisualBinRange';
-import { AggregateFunction, Bin, Brush, DoubleValueAggregateResult, HistogramResult, MarginAggregateParameters, MarginAggregateResult } from "../../northstar/model/idea/idea";
-import { ModelHelpers } from "../../northstar/model/ModelHelpers";
-import { LABColor } from '../../northstar/utils/LABColor';
-import { PIXIRectangle } from "../../northstar/utils/MathUtil";
-import { StyleConstants } from "../../northstar/utils/StyleContants";
-import { HistogramBox } from "./HistogramBox";
-import "./HistogramBoxPrimitives.scss";
-
-export class HistogramBinPrimitive {
-    constructor(init?: Partial<HistogramBinPrimitive>) {
-        Object.assign(this, init);
-    }
-    public DataValue: number = 0;
-    public Rect: PIXIRectangle = PIXIRectangle.EMPTY;
-    public MarginRect: PIXIRectangle = PIXIRectangle.EMPTY;
-    public MarginPercentage: number = 0;
-    public Color: number = StyleConstants.WARNING_COLOR;
-    public Opacity: number = 1;
-    public BrushIndex: number = 0;
-    public BarAxis: number = -1;
-}
-
-export class HistogramBinPrimitiveCollection {
-    private static TOLERANCE: number = 0.0001;
-
-    private _histoBox: HistogramBox;
-    private get histoOp() { return this._histoBox.HistoOp; }
-    private get histoResult() { return this.histoOp.Result as HistogramResult; }
-    private get sizeConverter() { return this._histoBox.SizeConverter; }
-    public BinPrimitives: Array<HistogramBinPrimitive> = new Array<HistogramBinPrimitive>();
-    public HitGeom: PIXIRectangle = PIXIRectangle.EMPTY;
-
-    constructor(bin: Bin, histoBox: HistogramBox) {
-        this._histoBox = histoBox;
-        let brushing = this.setupBrushing(bin, this.histoOp.Normalization); // X= 0, Y = 1, V = 2
-
-        brushing.orderedBrushes.reduce((brushFactorSum, brush) => {
-            switch (histoBox.ChartType) {
-                case ChartType.VerticalBar: return this.createVerticalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
-                case ChartType.HorizontalBar: return this.createHorizontalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
-                case ChartType.SinglePoint: return this.createSinglePointChartBinPrimitives(bin, brush);
-                case ChartType.HeatMap: return this.createHeatmapBinPrimitives(bin, brush, brushFactorSum);
-            }
-        }, 0);
-
-        // adjust brush rects (stacking or not)
-        var allBrushIndex = ModelHelpers.AllBrushIndex(this.histoResult);
-        var filteredBinPrims = this.BinPrimitives.filter(b => b.BrushIndex !== allBrushIndex && b.DataValue !== 0.0);
-        filteredBinPrims.reduce((sum, fbp) => {
-            if (histoBox.ChartType === ChartType.VerticalBar) {
-                if (this.histoOp.Y.AggregateFunction === AggregateFunction.Count) {
-                    fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y - sum, fbp.Rect.width, fbp.Rect.height);
-                    fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - sum, fbp.MarginRect.width, fbp.MarginRect.height);
-                    return sum + fbp.Rect.height;
-                }
-                if (this.histoOp.Y.AggregateFunction === AggregateFunction.Avg) {
-                    var w = fbp.Rect.width / 2.0;
-                    fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width / filteredBinPrims.length, fbp.Rect.height);
-                    fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x - w + sum + (fbp.Rect.width / 2.0), fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
-                    return sum + fbp.Rect.width;
-                }
-            }
-            else if (histoBox.ChartType === ChartType.HorizontalBar) {
-                if (this.histoOp.X.AggregateFunction === AggregateFunction.Count) {
-                    fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width, fbp.Rect.height);
-                    fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x + sum, fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
-                    return sum + fbp.Rect.width;
-                }
-                if (this.histoOp.X.AggregateFunction === AggregateFunction.Avg) {
-                    var h = fbp.Rect.height / 2.0;
-                    fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y + sum, fbp.Rect.width, fbp.Rect.height / filteredBinPrims.length);
-                    fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - h + sum + (fbp.Rect.height / 2.0), fbp.MarginRect.width, fbp.MarginRect.height);
-                    return sum + fbp.Rect.height;
-                }
-            }
-            return 0;
-        }, 0);
-        this.BinPrimitives = this.BinPrimitives.reverse();
-        var f = this.BinPrimitives.filter(b => b.BrushIndex === allBrushIndex);
-        this.HitGeom = f.length > 0 ? f[0].Rect : PIXIRectangle.EMPTY;
-    }
-
-    private setupBrushing(bin: Bin, normalization: number) {
-        var overlapBrushIndex = ModelHelpers.OverlapBrushIndex(this.histoResult);
-        var orderedBrushes = [this.histoResult.brushes![0], this.histoResult.brushes![overlapBrushIndex]];
-        this.histoResult.brushes!.map(brush => brush.brushIndex !== 0 && brush.brushIndex !== overlapBrushIndex && orderedBrushes.push(brush));
-        return {
-            orderedBrushes,
-            maxAxis: orderedBrushes.reduce((prev, Brush) => {
-                let aggResult = this.getBinValue(normalization, bin, Brush.brushIndex!);
-                return aggResult !== undefined && aggResult > prev ? aggResult : prev;
-            }, Number.MIN_VALUE)
-        };
-    }
-
-    private createHeatmapBinPrimitives(bin: Bin, brush: Brush, brushFactorSum: number): number {
-
-        let unNormalizedValue = this.getBinValue(2, bin, brush.brushIndex!);
-        if (unNormalizedValue === undefined) {
-            return brushFactorSum;
-        }
-
-        var normalizedValue = (unNormalizedValue - this._histoBox.ValueRange[0]) / (Math.abs((this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0])) < HistogramBinPrimitiveCollection.TOLERANCE ?
-            unNormalizedValue : this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0]);
-
-        let allUnNormalizedValue = this.getBinValue(2, bin, ModelHelpers.AllBrushIndex(this.histoResult));
-
-        // bcz: are these calls needed?  
-        let [xFrom, xTo] = this.sizeConverter.DataToScreenXAxisRange(this._histoBox.VisualBinRanges, 0, bin);
-        let [yFrom, yTo] = this.sizeConverter.DataToScreenYAxisRange(this._histoBox.VisualBinRanges, 1, bin);
-
-        var returnBrushFactorSum = brushFactorSum;
-        if (allUnNormalizedValue !== undefined) {
-            var brushFactor = (unNormalizedValue / allUnNormalizedValue);
-            returnBrushFactorSum += brushFactor;
-            returnBrushFactorSum = Math.min(returnBrushFactorSum, 1.0);
-
-            var tempRect = new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo);
-            var ratio = (tempRect.width / tempRect.height);
-            var newHeight = Math.sqrt((1.0 / ratio) * ((tempRect.width * tempRect.height) * returnBrushFactorSum));
-            var newWidth = newHeight * ratio;
-
-            xFrom = (tempRect.x + (tempRect.width - newWidth) / 2.0);
-            yTo = (tempRect.y + (tempRect.height - newHeight) / 2.0);
-            xTo = (xFrom + newWidth);
-            yFrom = (yTo + newHeight);
-        }
-        var alpha = 0.0;
-        var color = this.baseColorFromBrush(brush);
-        var lerpColor = LABColor.Lerp(
-            LABColor.FromColor(StyleConstants.MIN_VALUE_COLOR),
-            LABColor.FromColor(color),
-            (alpha + Math.pow(normalizedValue, 1.0 / 3.0) * (1.0 - alpha)));
-        var dataColor = LABColor.ToColor(lerpColor);
-
-        this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, dataColor, 1, unNormalizedValue);
-        return returnBrushFactorSum;
-    }
-
-    private createSinglePointChartBinPrimitives(bin: Bin, brush: Brush): number {
-        let unNormalizedValue = this.getBinValue(2, bin, brush.brushIndex!);
-        if (unNormalizedValue !== undefined) {
-            let [xFrom, xTo] = this.sizeConverter.DataToScreenPointRange(0, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, this.histoOp.X, this.histoResult, brush.brushIndex!));
-            let [yFrom, yTo] = this.sizeConverter.DataToScreenPointRange(1, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, this.histoOp.Y, this.histoResult, brush.brushIndex!));
-
-            if (xFrom !== undefined && yFrom !== undefined && xTo !== undefined && yTo !== undefined) {
-                this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, this.baseColorFromBrush(brush), 1, unNormalizedValue);
-            }
-        }
-        return 0;
-    }
-
-    private createVerticalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
-        let dataValue = this.getBinValue(1, bin, brush.brushIndex!);
-        if (dataValue !== undefined) {
-            let [yFrom, yValue, yTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 1, binBrushMaxAxis);
-            let [xFrom, xTo] = this.sizeConverter.DataToScreenXAxisRange(this._histoBox.VisualBinRanges, 0, bin);
-
-            var yMarginAbsolute = this.getMargin(bin, brush, this.histoOp.Y);
-            var marginRect = new PIXIRectangle(xFrom + (xTo - xFrom) / 2.0 - 1,
-                this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute), 2,
-                this.sizeConverter.DataToScreenY(yValue - yMarginAbsolute) - this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute));
-
-            this.createBinPrimitive(1, brush, marginRect, 0, xFrom, xTo, yFrom, yTo,
-                this.baseColorFromBrush(brush), normalization !== 0 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[1] + 0.4, dataValue);
-        }
-        return 0;
-    }
-
-    private createHorizontalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
-        let dataValue = this.getBinValue(0, bin, brush.brushIndex!);
-        if (dataValue !== undefined) {
-            let [xFrom, xValue, xTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 0, binBrushMaxAxis);
-            let [yFrom, yTo] = this.sizeConverter.DataToScreenYAxisRange(this._histoBox.VisualBinRanges, 1, bin);
-
-            var xMarginAbsolute = this.sizeConverter.IsSmall ? 0 : this.getMargin(bin, brush, this.histoOp.X);
-            var marginRect = new PIXIRectangle(this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
-                yTo + (yFrom - yTo) / 2.0 - 1,
-                this.sizeConverter.DataToScreenX(xValue + xMarginAbsolute) - this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
-                2.0);
-
-            this.createBinPrimitive(0, brush, marginRect, 0, xFrom, xTo, yFrom, yTo,
-                this.baseColorFromBrush(brush), normalization !== 1 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[0] + 0.4, dataValue);
-        }
-        return 0;
-    }
-
-    public getBinValue(axis: number, bin: Bin, brushIndex: number) {
-        var aggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, axis === 0 ? this.histoOp.X : axis === 1 ? this.histoOp.Y : this.histoOp.V, this.histoResult, brushIndex);
-        let dataValue = ModelHelpers.GetAggregateResult(bin, aggregateKey) as DoubleValueAggregateResult;
-        return dataValue !== null && dataValue.hasResult ? dataValue.result : undefined;
-    }
-
-    private getMargin(bin: Bin, brush: Brush, axis: AttributeTransformationModel) {
-        var marginParams = new MarginAggregateParameters();
-        marginParams.aggregateFunction = axis.AggregateFunction;
-        var marginAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, axis, this.histoResult, brush.brushIndex!, marginParams);
-        let aggResult = ModelHelpers.GetAggregateResult(bin, marginAggregateKey);
-        return aggResult instanceof MarginAggregateResult && aggResult.absolutMargin ? aggResult.absolutMargin : 0;
-    }
-
-    private createBinPrimitive(barAxis: number, brush: Brush, marginRect: PIXIRectangle,
-        marginPercentage: number, xFrom: number, xTo: number, yFrom: number, yTo: number, color: number, opacity: number, dataValue: number) {
-        var binPrimitive = new HistogramBinPrimitive(
-            {
-                Rect: new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo),
-                MarginRect: marginRect,
-                MarginPercentage: marginPercentage,
-                BrushIndex: brush.brushIndex,
-                Color: color,
-                Opacity: opacity,
-                DataValue: dataValue,
-                BarAxis: barAxis
-            });
-        this.BinPrimitives.push(binPrimitive);
-    }
-
-    private baseColorFromBrush(brush: Brush): number {
-        let bc = StyleConstants.BRUSH_COLORS;
-        if (brush.brushIndex === ModelHelpers.RestBrushIndex(this.histoResult)) {
-            return StyleConstants.HIGHLIGHT_COLOR;
-        }
-        else if (brush.brushIndex === ModelHelpers.OverlapBrushIndex(this.histoResult)) {
-            return StyleConstants.OVERLAP_COLOR;
-        }
-        else if (brush.brushIndex === ModelHelpers.AllBrushIndex(this.histoResult)) {
-            return 0x00ff00;
-        }
-        else if (bc.length > 0) {
-            return bc[brush.brushIndex! % bc.length];
-        }
-        // else if (this.histoOp.BrushColors.length > 0) {
-        //     return this.histoOp.BrushColors[brush.brushIndex! % this.histoOp.BrushColors.length];
-        // }
-        return StyleConstants.HIGHLIGHT_COLOR;
-    }
-}
diff --git a/src/client/northstar/dash-nodes/HistogramBox.scss b/src/client/northstar/dash-nodes/HistogramBox.scss
deleted file mode 100644
index 06d781263..000000000
--- a/src/client/northstar/dash-nodes/HistogramBox.scss
+++ /dev/null
@@ -1,40 +0,0 @@
-.histogrambox-container {
-    padding: 0vw;
-    position: absolute;
-    top: -50%;
-    left:-50%;
-    text-align: center;
-    width: 100%;
-    height: 100%;
-    background: black; 
-  }
-  .histogrambox-xaxislabel {
-    position:absolute;
-    left:0;
-    width:100%;
-    text-align: center;
-    bottom:0;
-    background: lightgray;
-    font-size: 14;
-    font-weight: bold;
-  }
-  .histogrambox-yaxislabel {
-    position:absolute;
-    height:100%;
-    width: 25px;
-    left:0;
-    bottom:0;
-    background: lightgray;
-  }
-  .histogrambox-yaxislabel-text {
-    position:absolute;
-    left:0;
-    width: 1000px;
-    transform-origin: 10px 10px;
-    transform: rotate(-90deg);
-    text-align: left;
-    font-size: 14;
-    font-weight: bold;
-    bottom: calc(50% - 25px);
-  }
-  
\ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx
deleted file mode 100644
index 8fee53fb9..000000000
--- a/src/client/northstar/dash-nodes/HistogramBox.tsx
+++ /dev/null
@@ -1,175 +0,0 @@
-import React = require("react");
-import { action, computed, observable, reaction, runInAction, trace } from "mobx";
-import { observer } from "mobx-react";
-import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
-import { ChartType, VisualBinRange } from '../../northstar/model/binRanges/VisualBinRange';
-import { VisualBinRangeHelper } from "../../northstar/model/binRanges/VisualBinRangeHelper";
-import { AggregateBinRange, AggregateFunction, BinRange, Catalog, DoubleValueAggregateResult, HistogramResult } from "../../northstar/model/idea/idea";
-import { ModelHelpers } from "../../northstar/model/ModelHelpers";
-import { HistogramOperation } from "../../northstar/operations/HistogramOperation";
-import { SizeConverter } from "../../northstar/utils/SizeConverter";
-import { DragManager } from "../../util/DragManager";
-import { FieldView, FieldViewProps } from "../../views/nodes/FieldView";
-import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
-import { HistogramField } from "../dash-fields/HistogramField";
-import "../utils/Extensions";
-import "./HistogramBox.scss";
-import { HistogramBoxPrimitives } from './HistogramBoxPrimitives';
-import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives";
-import { StyleConstants } from "../utils/StyleContants";
-import { Cast } from "../../../new_fields/Types";
-import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc";
-import { Id } from "../../../new_fields/FieldSymbols";
-
-
-@observer
-export class HistogramBox extends React.Component<FieldViewProps> {
-    public static LayoutString(fieldStr: string) { return FieldView.LayoutString(HistogramBox, fieldStr); }
-    private _dropXRef = React.createRef<HTMLDivElement>();
-    private _dropYRef = React.createRef<HTMLDivElement>();
-    private _dropXDisposer?: DragManager.DragDropDisposer;
-    private _dropYDisposer?: DragManager.DragDropDisposer;
-
-    @observable public HistoOp: HistogramOperation = HistogramOperation.Empty;
-    @observable public VisualBinRanges: VisualBinRange[] = [];
-    @observable public ValueRange: number[] = [];
-    @computed public get HistogramResult(): HistogramResult { return this.HistoOp.Result as HistogramResult; }
-    @observable public SizeConverter: SizeConverter = new SizeConverter();
-
-    @computed get createOperationParamsCache() { return this.HistoOp.CreateOperationParameters(); }
-    @computed get BinRanges() { return this.HistogramResult ? this.HistogramResult.binRanges : undefined; }
-    @computed get ChartType() {
-        return !this.BinRanges ? ChartType.SinglePoint : this.BinRanges[0] instanceof AggregateBinRange ?
-            (this.BinRanges[1] instanceof AggregateBinRange ? ChartType.SinglePoint : ChartType.HorizontalBar) :
-            this.BinRanges[1] instanceof AggregateBinRange ? ChartType.VerticalBar : ChartType.HeatMap;
-    }
-
-    @action
-    dropX = (e: Event, de: DragManager.DropEvent) => {
-        if (de.complete.docDragData) {
-            let h = Cast(de.complete.docDragData.draggedDocuments[0].data, HistogramField);
-            if (h) {
-                this.HistoOp.X = h.HistoOp.X;
-            }
-            e.stopPropagation();
-            e.preventDefault();
-        }
-    }
-    @action
-    dropY = (e: Event, de: DragManager.DropEvent) => {
-        if (de.complete.docDragData) {
-            let h = Cast(de.complete.docDragData.draggedDocuments[0].data, HistogramField);
-            if (h) {
-                this.HistoOp.Y = h.HistoOp.X;
-            }
-            e.stopPropagation();
-            e.preventDefault();
-        }
-    }
-
-    @action
-    xLabelPointerDown = (e: React.PointerEvent) => {
-        this.HistoOp.X = new AttributeTransformationModel(this.HistoOp.X.AttributeModel, this.HistoOp.X.AggregateFunction === AggregateFunction.None ? AggregateFunction.Count : AggregateFunction.None);
-    }
-    @action
-    yLabelPointerDown = (e: React.PointerEvent) => {
-        this.HistoOp.Y = new AttributeTransformationModel(this.HistoOp.Y.AttributeModel, this.HistoOp.Y.AggregateFunction === AggregateFunction.None ? AggregateFunction.Count : AggregateFunction.None);
-    }
-
-    componentDidMount() {
-        if (this._dropXRef.current) {
-            this._dropXDisposer = DragManager.MakeDropTarget(this._dropXRef.current, this.dropX.bind(this));
-        }
-        if (this._dropYRef.current) {
-            this._dropYDisposer = DragManager.MakeDropTarget(this._dropYRef.current, this.dropY.bind(this));
-        }
-        reaction(() => CurrentUserUtils.NorthstarDBCatalog, (catalog?: Catalog) => this.activateHistogramOperation(catalog), { fireImmediately: true });
-        reaction(() => [this.VisualBinRanges && this.VisualBinRanges.slice()], () => this.SizeConverter.SetVisualBinRanges(this.VisualBinRanges));
-        reaction(() => [this.props.PanelWidth(), this.props.PanelHeight()], (size: number[]) => this.SizeConverter.SetIsSmall(size[0] < 40 && size[1] < 40));
-        reaction(() => this.HistogramResult ? this.HistogramResult.binRanges : undefined,
-            (binRanges: BinRange[] | undefined) => {
-                if (binRanges) {
-                    this.VisualBinRanges.splice(0, this.VisualBinRanges.length, ...binRanges.map((br, ind) =>
-                        VisualBinRangeHelper.GetVisualBinRange(this.HistoOp.Schema!.distinctAttributeParameters, br, this.HistogramResult, ind ? this.HistoOp.Y : this.HistoOp.X, this.ChartType)));
-
-                    let valueAggregateKey = ModelHelpers.CreateAggregateKey(this.HistoOp.Schema!.distinctAttributeParameters, this.HistoOp.V, this.HistogramResult, ModelHelpers.AllBrushIndex(this.HistogramResult));
-                    this.ValueRange = Object.values(this.HistogramResult.bins!).reduce((prev, cur) => {
-                        let value = ModelHelpers.GetAggregateResult(cur, valueAggregateKey) as DoubleValueAggregateResult;
-                        return value && value.hasResult ? [Math.min(prev[0], value.result!), Math.max(prev[1], value.result!)] : prev;
-                    }, [Number.MAX_VALUE, Number.MIN_VALUE]);
-                }
-            });
-    }
-
-    componentWillUnmount() {
-        if (this._dropXDisposer) {
-            this._dropXDisposer();
-        }
-        if (this._dropYDisposer) {
-            this._dropYDisposer();
-        }
-    }
-
-    async activateHistogramOperation(catalog?: Catalog) {
-        if (catalog) {
-            let histoOp = await Cast(this.props.Document[this.props.fieldKey], HistogramField);
-            runInAction(() => {
-                this.HistoOp = histoOp ? histoOp.HistoOp : HistogramOperation.Empty;
-                if (this.HistoOp !== HistogramOperation.Empty) {
-                    reaction(() => DocListCast(this.props.Document.linkedFromDocs), (docs) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true });
-                    reaction(() => DocListCast(this.props.Document.brushingDocs).length,
-                        async () => {
-                            let brushingDocs = await DocListCastAsync(this.props.Document.brushingDocs);
-                            const proto = this.props.Document.proto;
-                            if (proto && brushingDocs) {
-                                let mapped = brushingDocs.map((brush, i) => {
-                                    brush.backgroundColor = StyleConstants.BRUSH_COLORS[i % StyleConstants.BRUSH_COLORS.length];
-                                    let brushed = DocListCast(brush.brushingDocs);
-                                    if (!brushed.length) return null;
-                                    return { l: brush, b: brushed[0][Id] === proto[Id] ? brushed[1] : brushed[0] };
-                                });
-                                runInAction(() => this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...mapped.filter(m => m) as { l: Doc, b: Doc }[]));
-                            }
-                        }, { fireImmediately: true });
-                    reaction(() => this.createOperationParamsCache, () => this.HistoOp.Update(), { fireImmediately: true });
-                }
-            });
-        }
-    }
-
-    @action
-    private onScrollWheel = (e: React.WheelEvent) => {
-        this.HistoOp.DrillDown(e.deltaY > 0);
-        e.stopPropagation();
-    }
-
-    render() {
-        let labelY = this.HistoOp && this.HistoOp.Y ? this.HistoOp.Y.PresentedName : "<...>";
-        let labelX = this.HistoOp && this.HistoOp.X ? this.HistoOp.X.PresentedName : "<...>";
-        let loff = this.SizeConverter.LeftOffset;
-        let toff = this.SizeConverter.TopOffset;
-        let roff = this.SizeConverter.RightOffset;
-        let boff = this.SizeConverter.BottomOffset;
-        return (
-            <div className="histogrambox-container" onWheel={this.onScrollWheel}>
-                <div className="histogrambox-yaxislabel" onPointerDown={this.yLabelPointerDown} ref={this._dropYRef} >
-                    <span className="histogrambox-yaxislabel-text">
-                        {labelY}
-                    </span>
-                </div>
-                <div className="histogrambox-primitives" style={{
-                    transform: `translate(${loff + 25}px, ${toff}px)`,
-                    width: `calc(100% - ${loff + roff + 25}px)`,
-                    height: `calc(100% - ${toff + boff}px)`,
-                }}>
-                    <HistogramLabelPrimitives HistoBox={this} />
-                    <HistogramBoxPrimitives HistoBox={this} />
-                </div>
-                <div className="histogrambox-xaxislabel" onPointerDown={this.xLabelPointerDown} ref={this._dropXRef} >
-                    {labelX}
-                </div>
-            </div>
-        );
-    }
-}
-
diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss
deleted file mode 100644
index 26203612a..000000000
--- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss
+++ /dev/null
@@ -1,42 +0,0 @@
-.histogramboxprimitives-container {
-    width: 100%;
-    height: 100%;
-}
-.histogramboxprimitives-border {
-    border: 3px;
-    pointer-events: none;
-    position: absolute;
-    fill:"transparent";
-    stroke: white;
-    stroke-width: 1px;
-}
-.histogramboxprimitives-bar {
-    position: absolute;
-    border: 1px;
-    border-style: solid;
-    border-color: #282828;
-    pointer-events: all;
-}
-
-.histogramboxprimitives-placer {
-    position: absolute;
-    pointer-events: none;
-    width: 100%;
-    height: 100%;
-}
-.histogramboxprimitives-svgContainer {
-    position: absolute;
-    top:0;
-    left:0;
-    width:100%;
-    height: 100%;
-}
-.histogramboxprimitives-line {
-    position: absolute;
-    background: darkGray;
-    stroke: darkGray;
-    stroke-width: 1px;
-    width:100%;
-    height:100%;
-    opacity: 0.4;
-}
\ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
deleted file mode 100644
index 66d91cc1d..000000000
--- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-import React = require("react");
-import { computed, observable, reaction, runInAction, trace, action } from "mobx";
-import { observer } from "mobx-react";
-import { Utils as DashUtils, emptyFunction } from '../../../Utils';
-import { FilterModel } from "../../northstar/core/filter/FilterModel";
-import { ModelHelpers } from "../../northstar/model/ModelHelpers";
-import { ArrayUtil } from "../../northstar/utils/ArrayUtil";
-import { LABColor } from '../../northstar/utils/LABColor';
-import { PIXIRectangle } from "../../northstar/utils/MathUtil";
-import { StyleConstants } from "../../northstar/utils/StyleContants";
-import { HistogramBinPrimitiveCollection, HistogramBinPrimitive } from "./HistogramBinPrimitiveCollection";
-import { HistogramBox } from "./HistogramBox";
-import "./HistogramBoxPrimitives.scss";
-
-export interface HistogramPrimitivesProps {
-    HistoBox: HistogramBox;
-}
-@observer
-export class HistogramBoxPrimitives extends React.Component<HistogramPrimitivesProps> {
-    private get histoOp() { return this.props.HistoBox.HistoOp; }
-    private get renderDimension() { return this.props.HistoBox.SizeConverter.RenderDimension; }
-    @observable _selectedPrims: HistogramBinPrimitive[] = [];
-    @computed get xaxislines() { return this.renderGridLinesAndLabels(0); }
-    @computed get yaxislines() { return this.renderGridLinesAndLabels(1); }
-    @computed get selectedPrimitives() { return this._selectedPrims.map(bp => this.drawRect(bp.Rect, bp.BarAxis, undefined, "border")); }
-    @computed get barPrimitives() {
-        let histoResult = this.props.HistoBox.HistogramResult;
-        if (!histoResult || !histoResult.bins || !this.props.HistoBox.VisualBinRanges.length) {
-            return (null);
-        }
-        let allBrushIndex = ModelHelpers.AllBrushIndex(histoResult);
-        return Object.keys(histoResult.bins).reduce((prims: JSX.Element[], key: string) => {
-            let drawPrims = new HistogramBinPrimitiveCollection(histoResult.bins![key], this.props.HistoBox);
-            let toggle = this.getSelectionToggle(drawPrims.BinPrimitives, allBrushIndex,
-                ModelHelpers.GetBinFilterModel(histoResult.bins![key], allBrushIndex, histoResult, this.histoOp.X, this.histoOp.Y));
-            drawPrims.BinPrimitives.filter(bp => bp.DataValue && bp.BrushIndex !== allBrushIndex).map(bp =>
-                prims.push(...[{ r: bp.Rect, c: bp.Color }, { r: bp.MarginRect, c: StyleConstants.MARGIN_BARS_COLOR }].map(pair => this.drawRect(pair.r, bp.BarAxis, pair.c, "bar", toggle))));
-            return prims;
-        }, [] as JSX.Element[]);
-    }
-
-    componentDidMount() {
-        reaction(() => this.props.HistoBox.HistoOp.FilterString, () => this._selectedPrims.length = this.histoOp.FilterModels.length = 0);
-    }
-
-    private getSelectionToggle(binPrimitives: HistogramBinPrimitive[], allBrushIndex: number, filterModel: FilterModel) {
-        let rawAllBrushPrim = ArrayUtil.FirstOrDefault(binPrimitives, bp => bp.BrushIndex === allBrushIndex);
-        if (!rawAllBrushPrim) {
-            return emptyFunction;
-        }
-        let allBrushPrim = rawAllBrushPrim;
-        return () => runInAction(() => {
-            if (ArrayUtil.Contains(this.histoOp.FilterModels, filterModel)) {
-                this._selectedPrims.splice(this._selectedPrims.indexOf(allBrushPrim), 1);
-                this.histoOp.RemoveFilterModels([filterModel]);
-            }
-            else {
-                this._selectedPrims.push(allBrushPrim);
-                this.histoOp.AddFilterModels([filterModel]);
-            }
-        });
-    }
-
-    private renderGridLinesAndLabels(axis: number) {
-        if (!this.props.HistoBox.SizeConverter.Initialized) {
-            return (null);
-        }
-        let labels = this.props.HistoBox.VisualBinRanges[axis].GetLabels();
-        return <svg className="histogramboxprimitives-svgContainer">
-            {labels.reduce((prims, binLabel, i) => {
-                let r = this.props.HistoBox.SizeConverter.DataToScreenRange(binLabel.minValue!, binLabel.maxValue!, axis);
-                prims.push(this.drawLine(r.xFrom, r.yFrom, axis === 0 ? 0 : r.xTo - r.xFrom, axis === 0 ? r.yTo - r.yFrom : 0));
-                if (i === labels.length - 1) {
-                    prims.push(this.drawLine(axis === 0 ? r.xTo : r.xFrom, axis === 0 ? r.yFrom : r.yTo, axis === 0 ? 0 : r.xTo - r.xFrom, axis === 0 ? r.yTo - r.yFrom : 0));
-                }
-                return prims;
-            }, [] as JSX.Element[])}
-        </svg>;
-    }
-
-    drawLine(xFrom: number, yFrom: number, width: number, height: number) {
-        if (height < 0) {
-            yFrom += height;
-            height = -height;
-        }
-        if (width < 0) {
-            xFrom += width;
-            width = -width;
-        }
-        let trans2Xpercent = `${(xFrom + width) / this.renderDimension * 100}%`;
-        let trans2Ypercent = `${(yFrom + height) / this.renderDimension * 100}%`;
-        let trans1Xpercent = `${xFrom / this.renderDimension * 100}%`;
-        let trans1Ypercent = `${yFrom / this.renderDimension * 100}%`;
-        return <line className="histogramboxprimitives-line" key={DashUtils.GenerateGuid()} x1={trans1Xpercent} x2={`${trans2Xpercent}`} y1={trans1Ypercent} y2={`${trans2Ypercent}`} />;
-    }
-    drawRect(r: PIXIRectangle, barAxis: number, color: number | undefined, classExt: string, tapHandler: () => void = emptyFunction) {
-        if (r.height < 0) {
-            r.y += r.height;
-            r.height = -r.height;
-        }
-        if (r.width < 0) {
-            r.x += r.width;
-            r.width = -r.width;
-        }
-        let transXpercent = `${r.x / this.renderDimension * 100}%`;
-        let transYpercent = `${r.y / this.renderDimension * 100}%`;
-        let widthXpercent = `${r.width / this.renderDimension * 100}%`;
-        let heightYpercent = `${r.height / this.renderDimension * 100}%`;
-        return (<rect className={`histogramboxprimitives-${classExt}`} key={DashUtils.GenerateGuid()} onPointerDown={(e: React.PointerEvent) => { if (e.button === 0) tapHandler(); }}
-            x={transXpercent} width={`${widthXpercent}`} y={transYpercent} height={`${heightYpercent}`} fill={color ? `${LABColor.RGBtoHexString(color)}` : "transparent"} />);
-    }
-    render() {
-        return <div className="histogramboxprimitives-container">
-            {this.xaxislines}
-            {this.yaxislines}
-            <svg className="histogramboxprimitives-svgContainer">
-                {this.barPrimitives}
-                {this.selectedPrimitives}
-            </svg>
-        </div>;
-    }
-}
diff --git a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.scss b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.scss
deleted file mode 100644
index 304d33771..000000000
--- a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-
-  .histogramLabelPrimitives-gridlabel {
-    position:absolute;
-    transform-origin: left top;
-    font-size: 11;
-    color:white;
-  }
-  .histogramLabelPrimitives-placer {
-    position:absolute;
-    width:100%;
-    height:100%;
-    pointer-events: none;
-  }
\ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx
deleted file mode 100644
index 62aebd3c6..000000000
--- a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import React = require("react");
-import { action, computed, reaction } from "mobx";
-import { observer } from "mobx-react";
-import { Utils as DashUtils } from '../../../Utils';
-import { NominalVisualBinRange } from "../model/binRanges/NominalVisualBinRange";
-import "../utils/Extensions";
-import { StyleConstants } from "../utils/StyleContants";
-import { HistogramBox } from "./HistogramBox";
-import "./HistogramLabelPrimitives.scss";
-import { HistogramPrimitivesProps } from "./HistogramBoxPrimitives";
-
-@observer
-export class HistogramLabelPrimitives extends React.Component<HistogramPrimitivesProps> {
-    componentDidMount() {
-        reaction(() => [this.props.HistoBox.props.PanelWidth(), this.props.HistoBox.SizeConverter.LeftOffset, this.props.HistoBox.VisualBinRanges.length],
-            (fields) => HistogramLabelPrimitives.computeLabelAngle(fields[0], fields[1], this.props.HistoBox), { fireImmediately: true });
-    }
-
-    @action
-    static computeLabelAngle(panelWidth: number, leftOffset: number, histoBox: HistogramBox) {
-        const textWidth = 30;
-        if (panelWidth > 0 && histoBox.VisualBinRanges.length && histoBox.VisualBinRanges[0] instanceof NominalVisualBinRange) {
-            let space = (panelWidth - leftOffset * 2) / histoBox.VisualBinRanges[0].GetBins().length;
-            histoBox.SizeConverter.SetLabelAngle(Math.min(Math.PI / 2, Math.max(Math.PI / 6, textWidth / space * Math.PI / 2)));
-        } else if (histoBox.SizeConverter.LabelAngle) {
-            histoBox.SizeConverter.SetLabelAngle(0);
-        }
-    }
-    @computed get xaxislines() { return this.renderGridLinesAndLabels(0); }
-    @computed get yaxislines() { return this.renderGridLinesAndLabels(1); }
-
-    private renderGridLinesAndLabels(axis: number) {
-        let sc = this.props.HistoBox.SizeConverter;
-        let vb = this.props.HistoBox.VisualBinRanges;
-        if (!vb.length || !sc.Initialized) {
-            return (null);
-        }
-        let dim = (axis === 0 ? this.props.HistoBox.props.PanelWidth() : this.props.HistoBox.props.PanelHeight()) / ((axis === 0 && vb[axis] instanceof NominalVisualBinRange) ?
-            (12 + 5) : //  (<number>FontStyles.AxisLabel.fontSize + 5)));
-            sc.MaxLabelSizes[axis].coords[axis] + 5);
-
-        let labels = vb[axis].GetLabels();
-        return labels.reduce((prims, binLabel, i) => {
-            let r = sc.DataToScreenRange(binLabel.minValue!, binLabel.maxValue!, axis);
-            if (i % Math.ceil(labels.length / dim) === 0 && binLabel.label) {
-                const label = binLabel.label.Truncate(StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS, "...");
-                const textHeight = 14; const textWidth = 30;
-                let xStart = (axis === 0 ? r.xFrom + (r.xTo - r.xFrom) / 2.0 : r.xFrom - 10 - textWidth);
-                let yStart = (axis === 1 ? r.yFrom - textHeight / 2 : r.yFrom);
-
-                if (axis === 0 && vb[axis] instanceof NominalVisualBinRange) {
-                    let space = (r.xTo - r.xFrom) / sc.RenderDimension * this.props.HistoBox.props.PanelWidth();
-                    xStart += Math.max(textWidth / 2, (1 - textWidth / space) * textWidth / 2) - textHeight / 2;
-                }
-
-                let xPercent = axis === 1 ? `${xStart}px` : `${xStart / sc.RenderDimension * 100}%`;
-                let yPercent = axis === 0 ? `${this.props.HistoBox.props.PanelHeight() - sc.BottomOffset - textHeight}px` : `${yStart / sc.RenderDimension * 100}%`;
-
-                prims.push(
-                    <div className="histogramLabelPrimitives-placer" key={DashUtils.GenerateGuid()} style={{ transform: `translate(${xPercent}, ${yPercent})` }}>
-                        <div className="histogramLabelPrimitives-gridlabel" style={{ transform: `rotate(${axis === 0 ? sc.LabelAngle : 0}rad)` }}>
-                            {label}
-                        </div>
-                    </div>
-                );
-            }
-            return prims;
-        }, [] as JSX.Element[]);
-    }
-
-    render() {
-        let xaxislines = this.xaxislines;
-        let yaxislines = this.yaxislines;
-        return <div className="histogramLabelPrimitives-container">
-            {xaxislines}
-            {yaxislines}
-        </div>;
-    }
-
-}
\ No newline at end of file
diff --git a/src/client/northstar/manager/Gateway.ts b/src/client/northstar/manager/Gateway.ts
deleted file mode 100644
index c541cce6a..000000000
--- a/src/client/northstar/manager/Gateway.ts
+++ /dev/null
@@ -1,299 +0,0 @@
-import { Catalog, OperationReference, Result, CompileResults } from "../model/idea/idea";
-import { computed, observable, action } from "mobx";
-
-export class Gateway {
-
-    private static _instance: Gateway;
-
-    private constructor() {
-    }
-
-    public static get Instance() {
-        return this._instance || (this._instance = new this());
-    }
-
-    public async GetCatalog(): Promise<Catalog> {
-        try {
-            const json = await this.MakeGetRequest("catalog");
-            const cat = Catalog.fromJS(json);
-            return cat;
-        }
-        catch (error) {
-            throw new Error("can not reach northstar's backend");
-        }
-    }
-
-    public async PostSchema(csvdata: string, schemaname: string): Promise<string> {
-        try {
-            const json = await this.MakePostJsonRequest("postSchema", { csv: csvdata, schema: schemaname });
-            // const cat = Catalog.fromJS(json);
-            // return cat;
-            return json;
-        }
-        catch (error) {
-            throw new Error("can not reach northstar's backend");
-        }
-    }
-
-    public async GetSchema(pathname: string, schemaname: string): Promise<Catalog> {
-        try {
-            const json = await this.MakeGetRequest("schema", undefined, { path: pathname, schema: schemaname });
-            const cat = Catalog.fromJS(json);
-            return cat;
-        }
-        catch (error) {
-            throw new Error("can not reach northstar's backend");
-        }
-    }
-
-    public async ClearCatalog(): Promise<void> {
-        try {
-            await this.MakePostJsonRequest("Datamart/ClearAllAugmentations", {});
-        }
-        catch (error) {
-            throw new Error("can not reach northstar's backend");
-        }
-    }
-
-    public async TerminateServer(): Promise<void> {
-        try {
-            const url = Gateway.ConstructUrl("terminateServer");
-            const response = await fetch(url,
-                {
-                    redirect: "follow",
-                    method: "POST",
-                    credentials: "include"
-                });
-        }
-        catch (error) {
-            throw new Error("can not reach northstar's backend");
-        }
-    }
-
-    public async Compile(data: any): Promise<CompileResults | undefined> {
-        const json = await this.MakePostJsonRequest("compile", data);
-        if (json !== null) {
-            const cr = CompileResults.fromJS(json);
-            return cr;
-        }
-    }
-
-    public async SubmitResult(data: any): Promise<void> {
-        try {
-            console.log(data);
-            const url = Gateway.ConstructUrl("submitProblem");
-            const response = await fetch(url,
-                {
-                    redirect: "follow",
-                    method: "POST",
-                    credentials: "include",
-                    body: JSON.stringify(data)
-                });
-        }
-        catch (error) {
-            throw new Error("can not reach northstar's backend");
-        }
-    }
-
-    public async SpecifyProblem(data: any): Promise<void> {
-        try {
-            console.log(data);
-            const url = Gateway.ConstructUrl("specifyProblem");
-            const response = await fetch(url,
-                {
-                    redirect: "follow",
-                    method: "POST",
-                    credentials: "include",
-                    body: JSON.stringify(data)
-                });
-        }
-        catch (error) {
-            throw new Error("can not reach northstar's backend");
-        }
-    }
-
-    public async ExportToScript(solutionId: string): Promise<string> {
-        try {
-            const url = Gateway.ConstructUrl("exportsolution/script/" + solutionId);
-            const response = await fetch(url,
-                {
-                    redirect: "follow",
-                    method: "GET",
-                    credentials: "include"
-                });
-            return await response.text();
-        }
-        catch (error) {
-            throw new Error("can not reach northstar's backend");
-        }
-    }
-
-
-    public async StartOperation(data: any): Promise<OperationReference | undefined> {
-        const json = await this.MakePostJsonRequest("operation", data);
-        if (json !== null) {
-            const or = OperationReference.fromJS(json);
-            return or;
-        }
-    }
-
-    public async GetResult(data: any): Promise<Result | undefined> {
-        const json = await this.MakePostJsonRequest("result", data);
-        if (json !== null) {
-            const res = Result.fromJS(json);
-            return res;
-        }
-    }
-
-    public async PauseOperation(data: any): Promise<void> {
-        const url = Gateway.ConstructUrl("pause");
-        await fetch(url,
-            {
-                redirect: "follow",
-                method: "POST",
-                credentials: "include",
-                body: JSON.stringify(data)
-            });
-    }
-
-    public async MakeGetRequest(endpoint: string, signal?: AbortSignal, params?: any): Promise<any> {
-        let url = !params ? Gateway.ConstructUrl(endpoint) :
-            (() => {
-                let newUrl = new URL(Gateway.ConstructUrl(endpoint));
-                Object.getOwnPropertyNames(params).map(prop =>
-                    newUrl.searchParams.append(prop, params[prop]));
-                return Gateway.ConstructUrl(endpoint) + newUrl.search;
-            })();
-
-        const response = await fetch(url,
-            {
-                redirect: "follow",
-                method: "GET",
-                credentials: "include",
-                signal
-            });
-        const json = await response.json();
-        return json;
-    }
-
-    public async MakePostJsonRequest(endpoint: string, data: any, signal?: AbortSignal): Promise<any> {
-        const url = Gateway.ConstructUrl(endpoint);
-        const response = await fetch(url,
-            {
-                redirect: "follow",
-                method: "POST",
-                credentials: "include",
-                body: JSON.stringify(data),
-                signal
-            });
-        const json = await response.json();
-        return json;
-    }
-
-
-    public static ConstructUrl(appendix: string): string {
-        let base = NorthstarSettings.Instance.ServerUrl;
-        if (base.slice(-1) === "/") {
-            base = base.slice(0, -1);
-        }
-        let url = base + "/" + NorthstarSettings.Instance.ServerApiPath + "/" + appendix;
-        return url;
-    }
-}
-
-declare var ENV: any;
-
-export class NorthstarSettings {
-    private _environment: any;
-
-    @observable
-    public ServerUrl: string = document.URL;
-
-    @observable
-    public ServerApiPath?: string;
-
-    @observable
-    public SampleSize?: number;
-
-    @observable
-    public XBins?: number;
-
-    @observable
-    public YBins?: number;
-
-    @observable
-    public SplashTimeInMS?: number;
-
-    @observable
-    public ShowFpsCounter?: boolean;
-
-    @observable
-    public IsMenuFixed?: boolean;
-
-    @observable
-    public ShowShutdownButton?: boolean;
-
-    @observable
-    public IsDarpa?: boolean;
-
-    @observable
-    public IsIGT?: boolean;
-
-    @observable
-    public DegreeOfParallelism?: number;
-
-    @observable
-    public ShowWarnings?: boolean;
-
-    @computed
-    public get IsDev(): boolean {
-        return ENV.IsDev;
-    }
-
-    @computed
-    public get TestDataFolderPath(): string {
-        return this.Origin + "testdata/";
-    }
-
-    @computed
-    public get Origin(): string {
-        return window.location.origin + "/";
-    }
-
-    private static _instance: NorthstarSettings;
-
-    @action
-    public UpdateEnvironment(environment: any): void {
-        /*let serverParam = new URL(document.URL).searchParams.get("serverUrl");
-        if (serverParam) {
-            if (serverParam === "debug") {
-                this.ServerUrl = `http://${window.location.hostname}:1234`;
-            }
-            else {
-                this.ServerUrl = serverParam;
-            }
-        }
-        else {
-            this.ServerUrl = environment["SERVER_URL"] ? environment["SERVER_URL"] : document.URL;
-        }*/
-        this.ServerUrl = environment.SERVER_URL ? environment.SERVER_URL : document.URL;
-        this.ServerApiPath = environment.SERVER_API_PATH;
-        this.SampleSize = environment.SAMPLE_SIZE;
-        this.XBins = environment.X_BINS;
-        this.YBins = environment.Y_BINS;
-        this.SplashTimeInMS = environment.SPLASH_TIME_IN_MS;
-        this.ShowFpsCounter = environment.SHOW_FPS_COUNTER;
-        this.ShowShutdownButton = environment.SHOW_SHUTDOWN_BUTTON;
-        this.IsMenuFixed = environment.IS_MENU_FIXED;
-        this.IsDarpa = environment.IS_DARPA;
-        this.IsIGT = environment.IS_IGT;
-        this.DegreeOfParallelism = environment.DEGREE_OF_PARALLISM;
-    }
-
-    public static get Instance(): NorthstarSettings {
-        if (!this._instance) {
-            this._instance = new NorthstarSettings();
-        }
-        return this._instance;
-    }
-}
diff --git a/src/client/northstar/model/ModelExtensions.ts b/src/client/northstar/model/ModelExtensions.ts
deleted file mode 100644
index 29f80d2d1..000000000
--- a/src/client/northstar/model/ModelExtensions.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { AttributeParameters, Brush, MarginAggregateParameters, SingleDimensionAggregateParameters, Solution } from '../model/idea/idea';
-import { Utils } from '../utils/Utils';
-
-import { FilterModel } from '../core/filter/FilterModel';
-
-(SingleDimensionAggregateParameters as any).prototype.Equals = function (other: Object) {
-    if (!Utils.EqualityHelper(this, other)) return false;
-    if (!Utils.EqualityHelper((this as SingleDimensionAggregateParameters).attributeParameters!,
-        (other as SingleDimensionAggregateParameters).attributeParameters!)) return false;
-    if (!((this as SingleDimensionAggregateParameters).attributeParameters! as any).Equals((other as SingleDimensionAggregateParameters).attributeParameters)) return false;
-    return true;
-};
-
-{
-    (AttributeParameters as any).prototype.Equals = function (other: AttributeParameters) {
-        return (this).constructor.name === (<any>other).constructor.name &&
-            this.rawName === other.rawName;
-    };
-}
-
-{
-    (Solution as any).prototype.Equals = function (other: Object) {
-        if (!Utils.EqualityHelper(this, other)) return false;
-        if ((this as Solution).solutionId !== (other as Solution).solutionId) return false;
-        return true;
-    };
-}
-
-{
-    (MarginAggregateParameters as any).prototype.Equals = function (other: Object) {
-        if (!Utils.EqualityHelper(this, other)) return false;
-        if (!Utils.EqualityHelper((this as SingleDimensionAggregateParameters).attributeParameters!,
-            (other as SingleDimensionAggregateParameters).attributeParameters!)) return false;
-        if (!((this as SingleDimensionAggregateParameters).attributeParameters! as any).Equals((other as SingleDimensionAggregateParameters).attributeParameters!)) return false;
-
-        if ((this as MarginAggregateParameters).aggregateFunction !== (other as MarginAggregateParameters).aggregateFunction) return false;
-        return true;
-    };
-}
-
-{
-    (Brush as any).prototype.Equals = function (other: Object) {
-        if (!Utils.EqualityHelper(this, other)) return false;
-        if ((this as Brush).brushEnum !== (other as Brush).brushEnum) return false;
-        if ((this as Brush).brushIndex !== (other as Brush).brushIndex) return false;
-        return true;
-    };
-}
\ No newline at end of file
diff --git a/src/client/northstar/model/ModelHelpers.ts b/src/client/northstar/model/ModelHelpers.ts
deleted file mode 100644
index 88e6e72b8..000000000
--- a/src/client/northstar/model/ModelHelpers.ts
+++ /dev/null
@@ -1,220 +0,0 @@
-
-import { action } from "mobx";
-import { AggregateFunction, AggregateKey, AggregateParameters, AttributeColumnParameters, AttributeParameters, AverageAggregateParameters, Bin, BinningParameters, Brush, BrushEnum, CountAggregateParameters, DataType, EquiWidthBinningParameters, HistogramResult, MarginAggregateParameters, SingleBinBinningParameters, SingleDimensionAggregateParameters, SumAggregateParameters, AggregateBinRange, NominalBinRange, AlphabeticBinRange, Predicate, Schema, Attribute, AttributeGroup, Exception, AttributeBackendParameters, AttributeCodeParameters } from '../model/idea/idea';
-import { ValueComparison } from "../core/filter/ValueComparision";
-import { ArrayUtil } from "../utils/ArrayUtil";
-import { AttributeModel, ColumnAttributeModel, BackendAttributeModel, CodeAttributeModel } from "../core/attribute/AttributeModel";
-import { FilterModel } from "../core/filter/FilterModel";
-import { AlphabeticVisualBinRange } from "./binRanges/AlphabeticVisualBinRange";
-import { NominalVisualBinRange } from "./binRanges/NominalVisualBinRange";
-import { VisualBinRangeHelper } from "./binRanges/VisualBinRangeHelper";
-import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
-import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
-
-export class ModelHelpers {
-
-    public static CreateAggregateKey(distinctAttributeParameters: AttributeParameters | undefined, atm: AttributeTransformationModel, histogramResult: HistogramResult,
-        brushIndex: number, aggParameters?: SingleDimensionAggregateParameters): AggregateKey {
-        {
-            if (aggParameters === undefined) {
-                aggParameters = ModelHelpers.GetAggregateParameter(distinctAttributeParameters, atm);
-            }
-            else {
-                aggParameters.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
-            }
-            return new AggregateKey(
-                {
-                    aggregateParameterIndex: ModelHelpers.GetAggregateParametersIndex(histogramResult, aggParameters),
-                    brushIndex: brushIndex
-                });
-        }
-    }
-
-    public static GetAggregateParametersIndex(histogramResult: HistogramResult, aggParameters?: AggregateParameters): number {
-        return Array.from(histogramResult.aggregateParameters!).findIndex((value, i, set) => {
-            if (set[i] instanceof CountAggregateParameters && value instanceof CountAggregateParameters) return true;
-            if (set[i] instanceof MarginAggregateParameters && value instanceof MarginAggregateParameters) return true;
-            if (set[i] instanceof SumAggregateParameters && value instanceof SumAggregateParameters) return true;
-            return false;
-        });
-    }
-
-    public static GetAggregateParameter(distinctAttributeParameters: AttributeParameters | undefined, atm: AttributeTransformationModel): AggregateParameters | undefined {
-        var aggParam: AggregateParameters | undefined;
-        if (atm.AggregateFunction === AggregateFunction.Avg) {
-            var avg = new AverageAggregateParameters();
-            avg.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
-            avg.distinctAttributeParameters = distinctAttributeParameters;
-            aggParam = avg;
-        }
-        else if (atm.AggregateFunction === AggregateFunction.Count) {
-            var cnt = new CountAggregateParameters();
-            cnt.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
-            cnt.distinctAttributeParameters = distinctAttributeParameters;
-            aggParam = cnt;
-        }
-        else if (atm.AggregateFunction === AggregateFunction.Sum) {
-            var sum = new SumAggregateParameters();
-            sum.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
-            sum.distinctAttributeParameters = distinctAttributeParameters;
-            aggParam = sum;
-        }
-        return aggParam;
-    }
-
-    public static GetAggregateParametersWithMargins(distinctAttributeParameters: AttributeParameters | undefined, atms: Array<AttributeTransformationModel>): Array<AggregateParameters> {
-        var aggregateParameters = new Array<AggregateParameters>();
-        atms.forEach(agg => {
-            var aggParams = ModelHelpers.GetAggregateParameter(distinctAttributeParameters, agg);
-            if (aggParams) {
-                aggregateParameters.push(aggParams);
-
-                var margin = new MarginAggregateParameters();
-                margin.aggregateFunction = agg.AggregateFunction;
-                margin.attributeParameters = ModelHelpers.GetAttributeParameters(agg.AttributeModel);
-                margin.distinctAttributeParameters = distinctAttributeParameters;
-                aggregateParameters.push(margin);
-            }
-        });
-
-        return aggregateParameters;
-    }
-
-    public static GetBinningParameters(attr: AttributeTransformationModel, nrOfBins: number, minvalue?: number, maxvalue?: number): BinningParameters {
-        if (attr.AggregateFunction === AggregateFunction.None) {
-            return new EquiWidthBinningParameters(
-                {
-                    attributeParameters: ModelHelpers.GetAttributeParameters(attr.AttributeModel),
-                    requestedNrOfBins: nrOfBins,
-                    minValue: minvalue,
-                    maxValue: maxvalue
-                });
-        }
-        else {
-            return new SingleBinBinningParameters(
-                {
-                    attributeParameters: ModelHelpers.GetAttributeParameters(attr.AttributeModel)
-                });
-        }
-    }
-
-    public static GetAttributeParametersFromAttributeModel(am: AttributeModel): AttributeParameters {
-        if (am instanceof ColumnAttributeModel) {
-            return new AttributeColumnParameters(
-                {
-                    rawName: am.CodeName,
-                    visualizationHints: am.VisualizationHints
-                });
-        }
-        else if (am instanceof BackendAttributeModel) {
-            return new AttributeBackendParameters(
-                {
-                    rawName: am.CodeName,
-                    visualizationHints: am.VisualizationHints,
-                    id: (am).Id
-                });
-        }
-        else if (am instanceof CodeAttributeModel) {
-            return new AttributeCodeParameters(
-                {
-                    rawName: am.CodeName,
-                    visualizationHints: am.VisualizationHints,
-                    code: (am).Code
-                });
-        }
-        else {
-            throw new Exception();
-        }
-    }
-
-    public static GetAttributeParameters(am: AttributeModel): AttributeParameters {
-        return this.GetAttributeParametersFromAttributeModel(am);
-    }
-
-    public static OverlapBrushIndex(histogramResult: HistogramResult): number {
-        var brush = ArrayUtil.First(histogramResult.brushes!, (b: any) => b.brushEnum === BrushEnum.Overlap);
-        return ModelHelpers.GetBrushIndex(histogramResult, brush);
-    }
-
-    public static AllBrushIndex(histogramResult: HistogramResult): number {
-        var brush = ArrayUtil.First(histogramResult.brushes!, (b: any) => b.brushEnum === BrushEnum.All);
-        return ModelHelpers.GetBrushIndex(histogramResult, brush);
-    }
-
-    public static RestBrushIndex(histogramResult: HistogramResult): number {
-        var brush = ArrayUtil.First(histogramResult.brushes!, (b: Brush) => b.brushEnum === BrushEnum.Rest);
-        return ModelHelpers.GetBrushIndex(histogramResult, brush);
-    }
-
-    public static GetBrushIndex(histogramResult: HistogramResult, brush: Brush): number {
-        return ArrayUtil.IndexOfWithEqual(histogramResult.brushes!, brush);
-    }
-
-    public static GetAggregateResult(bin: Bin, aggregateKey: AggregateKey) {
-        if (aggregateKey.aggregateParameterIndex === -1 || aggregateKey.brushIndex === -1) {
-            return null;
-        }
-        return bin.aggregateResults![aggregateKey.aggregateParameterIndex! * bin.ySize! + aggregateKey.brushIndex!];
-    }
-
-    @action
-    public static PossibleAggegationFunctions(atm: AttributeTransformationModel): Array<AggregateFunction> {
-        var ret = new Array<AggregateFunction>();
-        ret.push(AggregateFunction.None);
-        ret.push(AggregateFunction.Count);
-        if (atm.AttributeModel.DataType === DataType.Float ||
-            atm.AttributeModel.DataType === DataType.Double ||
-            atm.AttributeModel.DataType === DataType.Int) {
-            ret.push(AggregateFunction.Avg);
-            ret.push(AggregateFunction.Sum);
-        }
-        return ret;
-    }
-
-    public static GetBinFilterModel(
-        bin: Bin, brushIndex: number, histogramResult: HistogramResult,
-        xAom: AttributeTransformationModel, yAom: AttributeTransformationModel): FilterModel {
-        var dimensions: Array<AttributeTransformationModel> = [xAom, yAom];
-        var filterModel = new FilterModel();
-
-        for (var i = 0; i < histogramResult.binRanges!.length; i++) {
-            if (!(histogramResult.binRanges![i] instanceof AggregateBinRange)) {
-                var binRange = VisualBinRangeHelper.GetNonAggregateVisualBinRange(histogramResult.binRanges![i]);
-                var dataFrom = binRange.GetValueFromIndex(bin.binIndex!.indices![i]);
-                var dataTo = binRange.AddStep(dataFrom);
-
-                if (binRange instanceof NominalVisualBinRange) {
-                    var tt = binRange.GetLabel(dataFrom);
-                    filterModel.ValueComparisons.push(new ValueComparison(dimensions[i].AttributeModel, Predicate.EQUALS, tt));
-                }
-                else if (binRange instanceof AlphabeticVisualBinRange) {
-                    filterModel.ValueComparisons.push(new ValueComparison(dimensions[i].AttributeModel, Predicate.STARTS_WITH,
-                        binRange.GetLabel(dataFrom)));
-                }
-                else {
-                    filterModel.ValueComparisons.push(new ValueComparison(dimensions[i].AttributeModel, Predicate.GREATER_THAN_EQUAL, dataFrom));
-                    filterModel.ValueComparisons.push(new ValueComparison(dimensions[i].AttributeModel, Predicate.LESS_THAN, dataTo));
-                }
-            }
-        }
-
-        return filterModel;
-    }
-
-    public GetAllAttributes(schema: Schema) {
-        if (!schema || !schema.rootAttributeGroup) {
-            return [];
-        }
-        const recurs = (attrs: Attribute[], g: AttributeGroup) => {
-            if (g.attributes) {
-                attrs.push.apply(attrs, g.attributes);
-                if (g.attributeGroups) {
-                    g.attributeGroups.forEach(ng => recurs(attrs, ng));
-                }
-            }
-        };
-        const allAttributes: Attribute[] = new Array<Attribute>();
-        recurs(allAttributes, schema.rootAttributeGroup);
-        return allAttributes;
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts b/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts
deleted file mode 100644
index 120b034f2..000000000
--- a/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { AlphabeticBinRange, BinLabel } from '../../model/idea/idea';
-import { VisualBinRange } from './VisualBinRange';
-
-export class AlphabeticVisualBinRange extends VisualBinRange {
-    public DataBinRange: AlphabeticBinRange;
-
-    constructor(dataBinRange: AlphabeticBinRange) {
-        super();
-        this.DataBinRange = dataBinRange;
-    }
-
-    public AddStep(value: number): number {
-        return value + 1;
-    }
-
-    public GetValueFromIndex(index: number): number {
-        return index;
-    }
-
-    public GetBins(): number[] {
-        var bins = new Array<number>();
-        var idx = 0;
-        for (var key in this.DataBinRange.labelsValue) {
-            if (this.DataBinRange.labelsValue.hasOwnProperty(key)) {
-                bins.push(idx);
-                idx++;
-            }
-        }
-        return bins;
-    }
-
-    public GetLabel(value: number): string {
-        return this.DataBinRange.prefix + this.DataBinRange.valuesLabel![value];
-    }
-
-    public GetLabels(): Array<BinLabel> {
-        var labels = new Array<BinLabel>();
-        var count = 0;
-        for (var key in this.DataBinRange.valuesLabel) {
-            if (this.DataBinRange.valuesLabel.hasOwnProperty(key)) {
-                var value = this.DataBinRange.valuesLabel[key];
-                labels.push(new BinLabel({
-                    value: parseFloat(key),
-                    minValue: count++,
-                    maxValue: count,
-                    label: this.DataBinRange.prefix + value
-                }));
-            }
-        }
-        return labels;
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts b/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts
deleted file mode 100644
index 776e643cd..000000000
--- a/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-import { DateTimeBinRange, DateTimeStep, DateTimeStepGranularity } from '../idea/idea';
-import { VisualBinRange } from './VisualBinRange';
-
-export class DateTimeVisualBinRange extends VisualBinRange {
-    public DataBinRange: DateTimeBinRange;
-
-    constructor(dataBinRange: DateTimeBinRange) {
-        super();
-        this.DataBinRange = dataBinRange;
-    }
-
-    public AddStep(value: number): number {
-        return DateTimeVisualBinRange.AddToDateTimeTicks(value, this.DataBinRange.step!);
-    }
-
-    public GetValueFromIndex(index: number): number {
-        var v = this.DataBinRange.minValue!;
-        for (var i = 0; i < index; i++) {
-            v = this.AddStep(v);
-        }
-        return v;
-    }
-
-    public GetBins(): number[] {
-        var bins = new Array<number>();
-        for (var v: number = this.DataBinRange.minValue!;
-            v < this.DataBinRange.maxValue!;
-            v = DateTimeVisualBinRange.AddToDateTimeTicks(v, this.DataBinRange.step!)) {
-            bins.push(v);
-        }
-        return bins;
-    }
-
-    private pad(n: number, size: number) {
-        var sign = n < 0 ? '-' : '';
-        return sign + new Array(size).concat([Math.abs(n)]).join('0').slice(-size);
-    }
-
-
-    public GetLabel(value: number): string {
-        var dt = DateTimeVisualBinRange.TicksToDate(value);
-        if (this.DataBinRange.step!.dateTimeStepGranularity === DateTimeStepGranularity.Second ||
-            this.DataBinRange.step!.dateTimeStepGranularity === DateTimeStepGranularity.Minute) {
-            return ("" + this.pad(dt.getMinutes(), 2) + ":" + this.pad(dt.getSeconds(), 2));
-            //return dt.ToString("mm:ss");
-        }
-        else if (this.DataBinRange.step!.dateTimeStepGranularity === DateTimeStepGranularity.Hour) {
-            return (this.pad(dt.getHours(), 2) + ":" + this.pad(dt.getMinutes(), 2));
-            //return dt.ToString("HH:mm");
-        }
-        else if (this.DataBinRange.step!.dateTimeStepGranularity === DateTimeStepGranularity.Day) {
-            return ((dt.getMonth() + 1) + "/" + dt.getDate() + "/" + dt.getFullYear());
-            //return dt.ToString("MM/dd/yyyy");
-        }
-        else if (this.DataBinRange.step!.dateTimeStepGranularity === DateTimeStepGranularity.Month) {
-            //return dt.ToString("MM/yyyy");
-            return ((dt.getMonth() + 1) + "/" + dt.getFullYear());
-        }
-        else if (this.DataBinRange.step!.dateTimeStepGranularity === DateTimeStepGranularity.Year) {
-            return "" + dt.getFullYear();
-        }
-        return "n/a";
-    }
-
-    public static TicksToDate(ticks: number): Date {
-        var dd = new Date((ticks - 621355968000000000) / 10000);
-        dd.setMinutes(dd.getMinutes() + dd.getTimezoneOffset());
-        return dd;
-    }
-
-
-    public static DateToTicks(date: Date): number {
-        var copiedDate = new Date(date.getTime());
-        copiedDate.setMinutes(copiedDate.getMinutes() - copiedDate.getTimezoneOffset());
-        var t = copiedDate.getTime() * 10000 + 621355968000000000;
-        /*var dd = new Date((ticks - 621355968000000000) / 10000);
-        dd.setMinutes(dd.getMinutes() + dd.getTimezoneOffset());
-        return dd;*/
-        return t;
-    }
-
-    public static AddToDateTimeTicks(ticks: number, dateTimeStep: DateTimeStep): number {
-        var copiedDate = DateTimeVisualBinRange.TicksToDate(ticks);
-        var returnDate: Date = new Date(Date.now());
-        if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Second) {
-            returnDate = new Date(copiedDate.setSeconds(copiedDate.getSeconds() + dateTimeStep.dateTimeStepValue!));
-        }
-        else if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Minute) {
-            returnDate = new Date(copiedDate.setMinutes(copiedDate.getMinutes() + dateTimeStep.dateTimeStepValue!));
-        }
-        else if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Hour) {
-            returnDate = new Date(copiedDate.setHours(copiedDate.getHours() + dateTimeStep.dateTimeStepValue!));
-        }
-        else if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Day) {
-            returnDate = new Date(copiedDate.setDate(copiedDate.getDate() + dateTimeStep.dateTimeStepValue!));
-        }
-        else if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Month) {
-            returnDate = new Date(copiedDate.setMonth(copiedDate.getMonth() + dateTimeStep.dateTimeStepValue!));
-        }
-        else if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Year) {
-            returnDate = new Date(copiedDate.setFullYear(copiedDate.getFullYear() + dateTimeStep.dateTimeStepValue!));
-        }
-        return DateTimeVisualBinRange.DateToTicks(returnDate);
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/NominalVisualBinRange.ts b/src/client/northstar/model/binRanges/NominalVisualBinRange.ts
deleted file mode 100644
index 42509d797..000000000
--- a/src/client/northstar/model/binRanges/NominalVisualBinRange.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { NominalBinRange, BinLabel } from '../../model/idea/idea';
-import { VisualBinRange } from './VisualBinRange';
-
-export class NominalVisualBinRange extends VisualBinRange {
-    public DataBinRange: NominalBinRange;
-
-    constructor(dataBinRange: NominalBinRange) {
-        super();
-        this.DataBinRange = dataBinRange;
-    }
-
-    public AddStep(value: number): number {
-        return value + 1;
-    }
-
-    public GetValueFromIndex(index: number): number {
-        return index;
-    }
-
-    public GetBins(): number[] {
-        var bins = new Array<number>();
-        var idx = 0;
-        for (var key in this.DataBinRange.labelsValue) {
-            if (this.DataBinRange.labelsValue.hasOwnProperty(key)) {
-                bins.push(idx);
-                idx++;
-            }
-        }
-        return bins;
-    }
-
-    public GetLabel(value: number): string {
-        return this.DataBinRange.valuesLabel![value];
-    }
-
-    public GetLabels(): Array<BinLabel> {
-        var labels = new Array<BinLabel>();
-        var count = 0;
-        for (var key in this.DataBinRange.valuesLabel) {
-            if (this.DataBinRange.valuesLabel.hasOwnProperty(key)) {
-                var value = this.DataBinRange.valuesLabel[key];
-                labels.push(new BinLabel({
-                    value: parseFloat(key),
-                    minValue: count++,
-                    maxValue: count,
-                    label: value
-                }));
-            }
-        }
-        return labels;
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts b/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts
deleted file mode 100644
index 7bc097e1d..000000000
--- a/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-import { QuantitativeBinRange } from '../idea/idea';
-import { VisualBinRange } from './VisualBinRange';
-import { format } from "d3-format";
-
-export class QuantitativeVisualBinRange extends VisualBinRange {
-
-    public DataBinRange: QuantitativeBinRange;
-
-    constructor(dataBinRange: QuantitativeBinRange) {
-        super();
-        this.DataBinRange = dataBinRange;
-    }
-
-    public AddStep(value: number): number {
-        return value + this.DataBinRange.step!;
-    }
-
-    public GetValueFromIndex(index: number): number {
-        return this.DataBinRange.minValue! + (index * this.DataBinRange.step!);
-    }
-
-    public GetLabel(value: number): string {
-        return QuantitativeVisualBinRange.NumberFormatter(value);
-    }
-
-    public static NumberFormatter(val: number): string {
-        if (val === 0) {
-            return "0";
-        }
-        if (val < 1) {
-            /*if (val < Math.abs(0.001))  {
-                return val.toExponential(2);
-            }*/
-            return format(".3")(val);
-        }
-        return format("~s")(val);
-    }
-
-    public GetBins(): number[] {
-        const bins = new Array<number>();
-
-        for (let v: number = this.DataBinRange.minValue!; v < this.DataBinRange.maxValue!; v += this.DataBinRange.step!) {
-            bins.push(v);
-        }
-        return bins;
-    }
-
-    public static Initialize(dataMinValue: number, dataMaxValue: number, targetBinNumber: number, isIntegerRange: boolean): QuantitativeVisualBinRange {
-        const extent = QuantitativeVisualBinRange.getExtent(dataMinValue, dataMaxValue, targetBinNumber, isIntegerRange);
-        const dataBinRange = new QuantitativeBinRange();
-        dataBinRange.minValue = extent[0];
-        dataBinRange.maxValue = extent[1];
-        dataBinRange.step = extent[2];
-
-        return new QuantitativeVisualBinRange(dataBinRange);
-    }
-
-    private static getExtent(dataMin: number, dataMax: number, m: number, isIntegerRange: boolean): number[] {
-        if (dataMin === dataMax) {
-            // dataMin -= 0.1;
-            dataMax += 0.1;
-        }
-        const span = dataMax - dataMin;
-
-        let step = Math.pow(10, Math.floor(Math.log10(span / m)));
-        const err = m / span * step;
-
-        if (err <= .15) {
-            step *= 10;
-        }
-        else if (err <= .35) {
-            step *= 5;
-        }
-        else if (err <= .75) {
-            step *= 2;
-        }
-
-        if (isIntegerRange) {
-            step = Math.ceil(step);
-        }
-        const ret: number[] = new Array<number>(3);
-        const minDivStep = Math.floor(dataMin / step);
-        const maxDivStep = Math.floor(dataMax / step);
-        ret[0] = minDivStep * step; // Math.floor(Math.Round(dataMin, 8)/step)*step;
-        ret[1] = maxDivStep * step + step; // Math.floor(Math.Round(dataMax, 8)/step)*step + step;
-        ret[2] = step;
-
-        return ret;
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/VisualBinRange.ts b/src/client/northstar/model/binRanges/VisualBinRange.ts
deleted file mode 100644
index 449a22e91..000000000
--- a/src/client/northstar/model/binRanges/VisualBinRange.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { BinLabel } from '../../model/idea/idea';
-
-export abstract class VisualBinRange {
-
-    public abstract AddStep(value: number): number;
-
-    public abstract GetValueFromIndex(index: number): number;
-
-    public abstract GetBins(): Array<number>;
-
-    public GetLabel(value: number): string {
-        return value.toString();
-    }
-
-    public GetLabels(): Array<BinLabel> {
-        var labels = new Array<BinLabel>();
-        var bins = this.GetBins();
-        bins.forEach(b => {
-            labels.push(new BinLabel({
-                value: b,
-                minValue: b,
-                maxValue: this.AddStep(b),
-                label: this.GetLabel(b)
-            }));
-        });
-        return labels;
-    }
-}
-
-export enum ChartType {
-    HorizontalBar = 0, VerticalBar = 1, HeatMap = 2, SinglePoint = 3
-}
\ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts b/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts
deleted file mode 100644
index a92412686..000000000
--- a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-import { BinRange, NominalBinRange, QuantitativeBinRange, Exception, AlphabeticBinRange, DateTimeBinRange, AggregateBinRange, DoubleValueAggregateResult, HistogramResult, AttributeParameters } from "../idea/idea";
-import { VisualBinRange, ChartType } from "./VisualBinRange";
-import { NominalVisualBinRange } from "./NominalVisualBinRange";
-import { QuantitativeVisualBinRange } from "./QuantitativeVisualBinRange";
-import { AlphabeticVisualBinRange } from "./AlphabeticVisualBinRange";
-import { DateTimeVisualBinRange } from "./DateTimeVisualBinRange";
-import { NorthstarSettings } from "../../manager/Gateway";
-import { ModelHelpers } from "../ModelHelpers";
-import { AttributeTransformationModel } from "../../core/attribute/AttributeTransformationModel";
-
-export const SETTINGS_X_BINS = 15;
-export const SETTINGS_Y_BINS = 15;
-export const SETTINGS_SAMPLE_SIZE = 100000;
-
-export class VisualBinRangeHelper {
-
-    public static GetNonAggregateVisualBinRange(dataBinRange: BinRange): VisualBinRange {
-        if (dataBinRange instanceof NominalBinRange) {
-            return new NominalVisualBinRange(dataBinRange);
-        }
-        else if (dataBinRange instanceof QuantitativeBinRange) {
-            return new QuantitativeVisualBinRange(dataBinRange);
-        }
-        else if (dataBinRange instanceof AlphabeticBinRange) {
-            return new AlphabeticVisualBinRange(dataBinRange);
-        }
-        else if (dataBinRange instanceof DateTimeBinRange) {
-            return new DateTimeVisualBinRange(dataBinRange);
-        }
-        throw new Exception();
-    }
-
-    public static GetVisualBinRange(distinctAttributeParameters: AttributeParameters | undefined, dataBinRange: BinRange, histoResult: HistogramResult, attr: AttributeTransformationModel, chartType: ChartType): VisualBinRange {
-
-        if (!(dataBinRange instanceof AggregateBinRange)) {
-            return VisualBinRangeHelper.GetNonAggregateVisualBinRange(dataBinRange);
-        }
-        else {
-            var aggregateKey = ModelHelpers.CreateAggregateKey(distinctAttributeParameters, attr, histoResult, ModelHelpers.AllBrushIndex(histoResult));
-            var minValue = Number.MAX_VALUE;
-            var maxValue = Number.MIN_VALUE;
-            for (const brush of histoResult.brushes!) {
-                aggregateKey.brushIndex = brush.brushIndex;
-                for (var key in histoResult.bins) {
-                    if (histoResult.bins.hasOwnProperty(key)) {
-                        var bin = histoResult.bins[key];
-                        var res = <DoubleValueAggregateResult>ModelHelpers.GetAggregateResult(bin, aggregateKey);
-                        if (res && res.hasResult && res.result) {
-                            minValue = Math.min(minValue, res.result);
-                            maxValue = Math.max(maxValue, res.result);
-                        }
-                    }
-                }
-            }
-
-            let visualBinRange = QuantitativeVisualBinRange.Initialize(minValue, maxValue, 10, false);
-
-            if (chartType === ChartType.HorizontalBar || chartType === ChartType.VerticalBar) {
-                visualBinRange = QuantitativeVisualBinRange.Initialize(Math.min(0, minValue),
-                    Math.max(0, (visualBinRange).DataBinRange.maxValue!),
-                    SETTINGS_X_BINS, false);
-            }
-            else if (chartType === ChartType.SinglePoint) {
-                visualBinRange = QuantitativeVisualBinRange.Initialize(Math.min(0, minValue), Math.max(0, maxValue),
-                    SETTINGS_X_BINS, false);
-            }
-            return visualBinRange;
-        }
-    }
-}
diff --git a/src/client/northstar/model/idea/MetricTypeMapping.ts b/src/client/northstar/model/idea/MetricTypeMapping.ts
deleted file mode 100644
index e9759cf16..000000000
--- a/src/client/northstar/model/idea/MetricTypeMapping.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { MetricType } from "./Idea";
-import { Dictionary } from 'typescript-collections';
-
-
-export class MetricTypeMapping {
-
-    public static GetMetricInterpretation(metricType: MetricType): MetricInterpretation {
-        if (metricType === MetricType.Accuracy ||
-            metricType === MetricType.F1 ||
-            metricType === MetricType.F1Macro ||
-            metricType === MetricType.F1Micro ||
-            metricType === MetricType.JaccardSimilarityScore ||
-            metricType === MetricType.ObjectDetectionAveragePrecision ||
-            metricType === MetricType.Precision ||
-            metricType === MetricType.PrecisionAtTopK ||
-            metricType === MetricType.NormalizedMutualInformation ||
-            metricType === MetricType.Recall ||
-            metricType === MetricType.RocAucMacro ||
-            metricType === MetricType.RocAuc ||
-            metricType === MetricType.RocAucMicro ||
-            metricType === MetricType.RSquared) {
-            return MetricInterpretation.HigherIsBetter;
-        }
-        return MetricInterpretation.LowerIsBetter;
-    }
-}
-
-export enum MetricInterpretation {
-    HigherIsBetter, LowerIsBetter
-}
\ No newline at end of file
diff --git a/src/client/northstar/model/idea/idea.ts b/src/client/northstar/model/idea/idea.ts
deleted file mode 100644
index c73a822c7..000000000
--- a/src/client/northstar/model/idea/idea.ts
+++ /dev/null
@@ -1,8557 +0,0 @@
-/* tslint:disable */
-//----------------------
-// <auto-generated>
-//     Generated using the NSwag toolchain v11.19.2.0 (NJsonSchema v9.10.73.0 (Newtonsoft.Json v9.0.0.0)) (http://NSwag.org)
-// </auto-generated>
-//----------------------
-// ReSharper disable InconsistentNaming
-
-
-
-export enum AggregateFunction {
-    None = "None",
-    Sum = "Sum",
-    SumE = "SumE",
-    Count = "Count",
-    Min = "Min",
-    Max = "Max",
-    Avg = "Avg",
-}
-
-export abstract class AggregateParameters implements IAggregateParameters {
-
-    protected _discriminator: string;
-
-    public Equals(other: Object): boolean {
-        return this == other;
-    }
-    constructor(data?: IAggregateParameters) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-        this._discriminator = "AggregateParameters";
-    }
-
-    init(data?: any) {
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): AggregateParameters {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "AverageAggregateParameters") {
-            let result = new AverageAggregateParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "SingleDimensionAggregateParameters") {
-            throw new Error("The abstract class 'SingleDimensionAggregateParameters' cannot be instantiated.");
-        }
-        if (data["discriminator"] === "CountAggregateParameters") {
-            let result = new CountAggregateParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "KDEAggregateParameters") {
-            let result = new KDEAggregateParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "MarginAggregateParameters") {
-            let result = new MarginAggregateParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "MaxAggregateParameters") {
-            let result = new MaxAggregateParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "MinAggregateParameters") {
-            let result = new MinAggregateParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "SumAggregateParameters") {
-            let result = new SumAggregateParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "SumEstimationAggregateParameters") {
-            let result = new SumEstimationAggregateParameters();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'AggregateParameters' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["discriminator"] = this._discriminator;
-        return data;
-    }
-}
-
-export interface IAggregateParameters {
-}
-
-export abstract class SingleDimensionAggregateParameters extends AggregateParameters implements ISingleDimensionAggregateParameters {
-    attributeParameters?: AttributeParameters | undefined;
-    distinctAttributeParameters?: AttributeParameters | undefined;
-
-    constructor(data?: ISingleDimensionAggregateParameters) {
-        super(data);
-        this._discriminator = "SingleDimensionAggregateParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.attributeParameters = data["AttributeParameters"] ? AttributeParameters.fromJS(data["AttributeParameters"]) : <any>undefined;
-            this.distinctAttributeParameters = data["DistinctAttributeParameters"] ? AttributeParameters.fromJS(data["DistinctAttributeParameters"]) : <any>undefined;
-        }
-    }
-
-    static fromJS(data: any): SingleDimensionAggregateParameters {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "AverageAggregateParameters") {
-            let result = new AverageAggregateParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "CountAggregateParameters") {
-            let result = new CountAggregateParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "KDEAggregateParameters") {
-            let result = new KDEAggregateParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "MarginAggregateParameters") {
-            let result = new MarginAggregateParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "MaxAggregateParameters") {
-            let result = new MaxAggregateParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "MinAggregateParameters") {
-            let result = new MinAggregateParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "SumAggregateParameters") {
-            let result = new SumAggregateParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "SumEstimationAggregateParameters") {
-            let result = new SumEstimationAggregateParameters();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'SingleDimensionAggregateParameters' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["AttributeParameters"] = this.attributeParameters ? this.attributeParameters.toJSON() : <any>undefined;
-        data["DistinctAttributeParameters"] = this.distinctAttributeParameters ? this.distinctAttributeParameters.toJSON() : <any>undefined;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ISingleDimensionAggregateParameters extends IAggregateParameters {
-    attributeParameters?: AttributeParameters | undefined;
-    distinctAttributeParameters?: AttributeParameters | undefined;
-}
-
-export class AverageAggregateParameters extends SingleDimensionAggregateParameters implements IAverageAggregateParameters {
-
-    constructor(data?: IAverageAggregateParameters) {
-        super(data);
-        this._discriminator = "AverageAggregateParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): AverageAggregateParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new AverageAggregateParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IAverageAggregateParameters extends ISingleDimensionAggregateParameters {
-}
-
-export abstract class AttributeParameters implements IAttributeParameters {
-    visualizationHints?: VisualizationHint[] | undefined;
-    rawName?: string | undefined;
-    public Equals(other: Object): boolean {
-        return this == other;
-    }
-
-    protected _discriminator: string;
-
-    constructor(data?: IAttributeParameters) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-        this._discriminator = "AttributeParameters";
-    }
-
-    init(data?: any) {
-        if (data) {
-            if (data["VisualizationHints"] && data["VisualizationHints"].constructor === Array) {
-                this.visualizationHints = [];
-                for (let item of data["VisualizationHints"])
-                    this.visualizationHints.push(item);
-            }
-            this.rawName = data["RawName"];
-        }
-    }
-
-    static fromJS(data: any): AttributeParameters {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "AttributeBackendParameters") {
-            let result = new AttributeBackendParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "AttributeCaclculatedParameters") {
-            throw new Error("The abstract class 'AttributeCaclculatedParameters' cannot be instantiated.");
-        }
-        if (data["discriminator"] === "AttributeCodeParameters") {
-            let result = new AttributeCodeParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "AttributeColumnParameters") {
-            let result = new AttributeColumnParameters();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'AttributeParameters' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["discriminator"] = this._discriminator;
-        if (this.visualizationHints && this.visualizationHints.constructor === Array) {
-            data["VisualizationHints"] = [];
-            for (let item of this.visualizationHints)
-                data["VisualizationHints"].push(item);
-        }
-        data["RawName"] = this.rawName;
-        return data;
-    }
-}
-
-export interface IAttributeParameters {
-    visualizationHints?: VisualizationHint[] | undefined;
-    rawName?: string | undefined;
-}
-
-export enum VisualizationHint {
-    TreatAsEnumeration = "TreatAsEnumeration",
-    DefaultFlipAxis = "DefaultFlipAxis",
-    Image = "Image",
-}
-
-export abstract class AttributeCaclculatedParameters extends AttributeParameters implements IAttributeCaclculatedParameters {
-
-    constructor(data?: IAttributeCaclculatedParameters) {
-        super(data);
-        this._discriminator = "AttributeCaclculatedParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): AttributeCaclculatedParameters {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "AttributeBackendParameters") {
-            let result = new AttributeBackendParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "AttributeCodeParameters") {
-            let result = new AttributeCodeParameters();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'AttributeCaclculatedParameters' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IAttributeCaclculatedParameters extends IAttributeParameters {
-}
-
-export class AttributeBackendParameters extends AttributeCaclculatedParameters implements IAttributeBackendParameters {
-    id?: string | undefined;
-
-    constructor(data?: IAttributeBackendParameters) {
-        super(data);
-        this._discriminator = "AttributeBackendParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.id = data["Id"];
-        }
-    }
-
-    static fromJS(data: any): AttributeBackendParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new AttributeBackendParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Id"] = this.id;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IAttributeBackendParameters extends IAttributeCaclculatedParameters {
-    id?: string | undefined;
-}
-
-export class AttributeCodeParameters extends AttributeCaclculatedParameters implements IAttributeCodeParameters {
-    code?: string | undefined;
-
-    constructor(data?: IAttributeCodeParameters) {
-        super(data);
-        this._discriminator = "AttributeCodeParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.code = data["Code"];
-        }
-    }
-
-    static fromJS(data: any): AttributeCodeParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new AttributeCodeParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Code"] = this.code;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IAttributeCodeParameters extends IAttributeCaclculatedParameters {
-    code?: string | undefined;
-}
-
-export class AttributeColumnParameters extends AttributeParameters implements IAttributeColumnParameters {
-
-    constructor(data?: IAttributeColumnParameters) {
-        super(data);
-        this._discriminator = "AttributeColumnParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): AttributeColumnParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new AttributeColumnParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IAttributeColumnParameters extends IAttributeParameters {
-}
-
-export class CountAggregateParameters extends SingleDimensionAggregateParameters implements ICountAggregateParameters {
-
-    constructor(data?: ICountAggregateParameters) {
-        super(data);
-        this._discriminator = "CountAggregateParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): CountAggregateParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new CountAggregateParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ICountAggregateParameters extends ISingleDimensionAggregateParameters {
-}
-
-export class KDEAggregateParameters extends SingleDimensionAggregateParameters implements IKDEAggregateParameters {
-    nrOfSamples?: number | undefined;
-
-    constructor(data?: IKDEAggregateParameters) {
-        super(data);
-        this._discriminator = "KDEAggregateParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.nrOfSamples = data["NrOfSamples"];
-        }
-    }
-
-    static fromJS(data: any): KDEAggregateParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new KDEAggregateParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["NrOfSamples"] = this.nrOfSamples;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IKDEAggregateParameters extends ISingleDimensionAggregateParameters {
-    nrOfSamples?: number | undefined;
-}
-
-export class MarginAggregateParameters extends SingleDimensionAggregateParameters implements IMarginAggregateParameters {
-    aggregateFunction?: AggregateFunction | undefined;
-
-    constructor(data?: IMarginAggregateParameters) {
-        super(data);
-        this._discriminator = "MarginAggregateParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.aggregateFunction = data["AggregateFunction"];
-        }
-    }
-
-    static fromJS(data: any): MarginAggregateParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new MarginAggregateParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["AggregateFunction"] = this.aggregateFunction;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IMarginAggregateParameters extends ISingleDimensionAggregateParameters {
-    aggregateFunction?: AggregateFunction | undefined;
-}
-
-export class MaxAggregateParameters extends SingleDimensionAggregateParameters implements IMaxAggregateParameters {
-
-    constructor(data?: IMaxAggregateParameters) {
-        super(data);
-        this._discriminator = "MaxAggregateParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): MaxAggregateParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new MaxAggregateParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IMaxAggregateParameters extends ISingleDimensionAggregateParameters {
-}
-
-export class MinAggregateParameters extends SingleDimensionAggregateParameters implements IMinAggregateParameters {
-
-    constructor(data?: IMinAggregateParameters) {
-        super(data);
-        this._discriminator = "MinAggregateParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): MinAggregateParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new MinAggregateParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IMinAggregateParameters extends ISingleDimensionAggregateParameters {
-}
-
-export class SumAggregateParameters extends SingleDimensionAggregateParameters implements ISumAggregateParameters {
-
-    constructor(data?: ISumAggregateParameters) {
-        super(data);
-        this._discriminator = "SumAggregateParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): SumAggregateParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new SumAggregateParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ISumAggregateParameters extends ISingleDimensionAggregateParameters {
-}
-
-export class SumEstimationAggregateParameters extends SingleDimensionAggregateParameters implements ISumEstimationAggregateParameters {
-
-    constructor(data?: ISumEstimationAggregateParameters) {
-        super(data);
-        this._discriminator = "SumEstimationAggregateParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): SumEstimationAggregateParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new SumEstimationAggregateParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ISumEstimationAggregateParameters extends ISingleDimensionAggregateParameters {
-}
-
-export enum OrderingFunction {
-    None = 0,
-    SortUp = 1,
-    SortDown = 2,
-}
-
-export abstract class BinningParameters implements IBinningParameters {
-    attributeParameters?: AttributeParameters | undefined;
-
-    protected _discriminator: string;
-
-    constructor(data?: IBinningParameters) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-        this._discriminator = "BinningParameters";
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.attributeParameters = data["AttributeParameters"] ? AttributeParameters.fromJS(data["AttributeParameters"]) : <any>undefined;
-        }
-    }
-
-    static fromJS(data: any): BinningParameters {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "EquiWidthBinningParameters") {
-            let result = new EquiWidthBinningParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "SingleBinBinningParameters") {
-            let result = new SingleBinBinningParameters();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'BinningParameters' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["discriminator"] = this._discriminator;
-        data["AttributeParameters"] = this.attributeParameters ? this.attributeParameters.toJSON() : <any>undefined;
-        return data;
-    }
-}
-
-export interface IBinningParameters {
-    attributeParameters?: AttributeParameters | undefined;
-}
-
-export class EquiWidthBinningParameters extends BinningParameters implements IEquiWidthBinningParameters {
-    minValue?: number | undefined;
-    maxValue?: number | undefined;
-    requestedNrOfBins?: number | undefined;
-    referenceValue?: number | undefined;
-    step?: number | undefined;
-
-    constructor(data?: IEquiWidthBinningParameters) {
-        super(data);
-        this._discriminator = "EquiWidthBinningParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.minValue = data["MinValue"];
-            this.maxValue = data["MaxValue"];
-            this.requestedNrOfBins = data["RequestedNrOfBins"];
-            this.referenceValue = data["ReferenceValue"];
-            this.step = data["Step"];
-        }
-    }
-
-    static fromJS(data: any): EquiWidthBinningParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new EquiWidthBinningParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["MinValue"] = this.minValue;
-        data["MaxValue"] = this.maxValue;
-        data["RequestedNrOfBins"] = this.requestedNrOfBins;
-        data["ReferenceValue"] = this.referenceValue;
-        data["Step"] = this.step;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IEquiWidthBinningParameters extends IBinningParameters {
-    minValue?: number | undefined;
-    maxValue?: number | undefined;
-    requestedNrOfBins?: number | undefined;
-    referenceValue?: number | undefined;
-    step?: number | undefined;
-}
-
-export class SingleBinBinningParameters extends BinningParameters implements ISingleBinBinningParameters {
-
-    constructor(data?: ISingleBinBinningParameters) {
-        super(data);
-        this._discriminator = "SingleBinBinningParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): SingleBinBinningParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new SingleBinBinningParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ISingleBinBinningParameters extends IBinningParameters {
-}
-
-export class Attribute implements IAttribute {
-    displayName?: string | undefined;
-    rawName?: string | undefined;
-    description?: string | undefined;
-    dataType?: DataType | undefined;
-    visualizationHints?: VisualizationHint[] | undefined;
-    isTarget?: boolean | undefined;
-
-    constructor(data?: IAttribute) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.displayName = data["DisplayName"];
-            this.rawName = data["RawName"];
-            this.description = data["Description"];
-            this.dataType = data["DataType"];
-            if (data["VisualizationHints"] && data["VisualizationHints"].constructor === Array) {
-                this.visualizationHints = [];
-                for (let item of data["VisualizationHints"])
-                    this.visualizationHints.push(item);
-            }
-            this.isTarget = data["IsTarget"];
-        }
-    }
-
-    static fromJS(data: any): Attribute {
-        data = typeof data === 'object' ? data : {};
-        let result = new Attribute();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["DisplayName"] = this.displayName;
-        data["RawName"] = this.rawName;
-        data["Description"] = this.description;
-        data["DataType"] = this.dataType;
-        if (this.visualizationHints && this.visualizationHints.constructor === Array) {
-            data["VisualizationHints"] = [];
-            for (let item of this.visualizationHints)
-                data["VisualizationHints"].push(item);
-        }
-        data["IsTarget"] = this.isTarget;
-        return data;
-    }
-}
-
-export interface IAttribute {
-    displayName?: string | undefined;
-    rawName?: string | undefined;
-    description?: string | undefined;
-    dataType?: DataType | undefined;
-    visualizationHints?: VisualizationHint[] | undefined;
-    isTarget?: boolean | undefined;
-}
-
-export enum DataType {
-    Int = "Int",
-    String = "String",
-    Float = "Float",
-    Double = "Double",
-    DateTime = "DateTime",
-    Object = "Object",
-    Undefined = "Undefined",
-}
-
-export class AttributeGroup implements IAttributeGroup {
-    name?: string | undefined;
-    attributeGroups?: AttributeGroup[] | undefined;
-    attributes?: Attribute[] | undefined;
-
-    constructor(data?: IAttributeGroup) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.name = data["Name"];
-            if (data["AttributeGroups"] && data["AttributeGroups"].constructor === Array) {
-                this.attributeGroups = [];
-                for (let item of data["AttributeGroups"])
-                    this.attributeGroups.push(AttributeGroup.fromJS(item));
-            }
-            if (data["Attributes"] && data["Attributes"].constructor === Array) {
-                this.attributes = [];
-                for (let item of data["Attributes"])
-                    this.attributes.push(Attribute.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): AttributeGroup {
-        data = typeof data === 'object' ? data : {};
-        let result = new AttributeGroup();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Name"] = this.name;
-        if (this.attributeGroups && this.attributeGroups.constructor === Array) {
-            data["AttributeGroups"] = [];
-            for (let item of this.attributeGroups)
-                data["AttributeGroups"].push(item.toJSON());
-        }
-        if (this.attributes && this.attributes.constructor === Array) {
-            data["Attributes"] = [];
-            for (let item of this.attributes)
-                data["Attributes"].push(item.toJSON());
-        }
-        return data;
-    }
-}
-
-export interface IAttributeGroup {
-    name?: string | undefined;
-    attributeGroups?: AttributeGroup[] | undefined;
-    attributes?: Attribute[] | undefined;
-}
-
-export class Catalog implements ICatalog {
-    supportedOperations?: string[] | undefined;
-    schemas?: Schema[] | undefined;
-
-    constructor(data?: ICatalog) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            if (data["SupportedOperations"] && data["SupportedOperations"].constructor === Array) {
-                this.supportedOperations = [];
-                for (let item of data["SupportedOperations"])
-                    this.supportedOperations.push(item);
-            }
-            if (data["Schemas"] && data["Schemas"].constructor === Array) {
-                this.schemas = [];
-                for (let item of data["Schemas"])
-                    this.schemas.push(Schema.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): Catalog {
-        data = typeof data === 'object' ? data : {};
-        let result = new Catalog();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.supportedOperations && this.supportedOperations.constructor === Array) {
-            data["SupportedOperations"] = [];
-            for (let item of this.supportedOperations)
-                data["SupportedOperations"].push(item);
-        }
-        if (this.schemas && this.schemas.constructor === Array) {
-            data["Schemas"] = [];
-            for (let item of this.schemas)
-                data["Schemas"].push(item.toJSON());
-        }
-        return data;
-    }
-}
-
-export interface ICatalog {
-    supportedOperations?: string[] | undefined;
-    schemas?: Schema[] | undefined;
-}
-
-export class Schema implements ISchema {
-    rootAttributeGroup?: AttributeGroup | undefined;
-    displayName?: string | undefined;
-    augmentedFrom?: string | undefined;
-    rawName?: string | undefined;
-    problemDescription?: string | undefined;
-    darpaProblemDoc?: DarpaProblemDoc | undefined;
-    distinctAttributeParameters?: AttributeParameters | undefined;
-    darpaDatasetDoc?: DarpaDatasetDoc | undefined;
-    darpaDatasetLocation?: string | undefined;
-    isMultiResourceData?: boolean | undefined;
-    problemFinderRows?: ProblemFinderRows[] | undefined;
-    correlationRows?: ProblemFinderRows[] | undefined;
-
-    constructor(data?: ISchema) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.rootAttributeGroup = data["RootAttributeGroup"] ? AttributeGroup.fromJS(data["RootAttributeGroup"]) : <any>undefined;
-            this.displayName = data["DisplayName"];
-            this.augmentedFrom = data["AugmentedFrom"];
-            this.rawName = data["RawName"];
-            this.problemDescription = data["ProblemDescription"];
-            this.darpaProblemDoc = data["DarpaProblemDoc"] ? DarpaProblemDoc.fromJS(data["DarpaProblemDoc"]) : <any>undefined;
-            this.distinctAttributeParameters = data["DistinctAttributeParameters"] ? AttributeParameters.fromJS(data["DistinctAttributeParameters"]) : <any>undefined;
-            this.darpaDatasetDoc = data["DarpaDatasetDoc"] ? DarpaDatasetDoc.fromJS(data["DarpaDatasetDoc"]) : <any>undefined;
-            this.darpaDatasetLocation = data["DarpaDatasetLocation"];
-            this.isMultiResourceData = data["IsMultiResourceData"];
-            if (data["ProblemFinderRows"] && data["ProblemFinderRows"].constructor === Array) {
-                this.problemFinderRows = [];
-                for (let item of data["ProblemFinderRows"])
-                    this.problemFinderRows.push(ProblemFinderRows.fromJS(item));
-            }
-            if (data["CorrelationRows"] && data["CorrelationRows"].constructor === Array) {
-                this.correlationRows = [];
-                for (let item of data["CorrelationRows"])
-                    this.correlationRows.push(ProblemFinderRows.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): Schema {
-        data = typeof data === 'object' ? data : {};
-        let result = new Schema();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["RootAttributeGroup"] = this.rootAttributeGroup ? this.rootAttributeGroup.toJSON() : <any>undefined;
-        data["DisplayName"] = this.displayName;
-        data["AugmentedFrom"] = this.augmentedFrom;
-        data["RawName"] = this.rawName;
-        data["ProblemDescription"] = this.problemDescription;
-        data["DarpaProblemDoc"] = this.darpaProblemDoc ? this.darpaProblemDoc.toJSON() : <any>undefined;
-        data["DistinctAttributeParameters"] = this.distinctAttributeParameters ? this.distinctAttributeParameters.toJSON() : <any>undefined;
-        data["DarpaDatasetDoc"] = this.darpaDatasetDoc ? this.darpaDatasetDoc.toJSON() : <any>undefined;
-        data["DarpaDatasetLocation"] = this.darpaDatasetLocation;
-        data["IsMultiResourceData"] = this.isMultiResourceData;
-        if (this.problemFinderRows && this.problemFinderRows.constructor === Array) {
-            data["ProblemFinderRows"] = [];
-            for (let item of this.problemFinderRows)
-                data["ProblemFinderRows"].push(item.toJSON());
-        }
-        if (this.correlationRows && this.correlationRows.constructor === Array) {
-            data["CorrelationRows"] = [];
-            for (let item of this.correlationRows)
-                data["CorrelationRows"].push(item.toJSON());
-        }
-        return data;
-    }
-}
-
-export interface ISchema {
-    rootAttributeGroup?: AttributeGroup | undefined;
-    displayName?: string | undefined;
-    augmentedFrom?: string | undefined;
-    rawName?: string | undefined;
-    problemDescription?: string | undefined;
-    darpaProblemDoc?: DarpaProblemDoc | undefined;
-    distinctAttributeParameters?: AttributeParameters | undefined;
-    darpaDatasetDoc?: DarpaDatasetDoc | undefined;
-    darpaDatasetLocation?: string | undefined;
-    isMultiResourceData?: boolean | undefined;
-    problemFinderRows?: ProblemFinderRows[] | undefined;
-    correlationRows?: ProblemFinderRows[] | undefined;
-}
-
-export class DarpaProblemDoc implements IDarpaProblemDoc {
-    about?: ProblemAbout | undefined;
-    inputs?: ProblemInputs | undefined;
-
-    constructor(data?: IDarpaProblemDoc) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.about = data["about"] ? ProblemAbout.fromJS(data["about"]) : <any>undefined;
-            this.inputs = data["inputs"] ? ProblemInputs.fromJS(data["inputs"]) : <any>undefined;
-        }
-    }
-
-    static fromJS(data: any): DarpaProblemDoc {
-        data = typeof data === 'object' ? data : {};
-        let result = new DarpaProblemDoc();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["about"] = this.about ? this.about.toJSON() : <any>undefined;
-        data["inputs"] = this.inputs ? this.inputs.toJSON() : <any>undefined;
-        return data;
-    }
-}
-
-export interface IDarpaProblemDoc {
-    about?: ProblemAbout | undefined;
-    inputs?: ProblemInputs | undefined;
-}
-
-export class ProblemAbout implements IProblemAbout {
-    problemID?: string | undefined;
-    problemName?: string | undefined;
-    problemDescription?: string | undefined;
-    taskType?: string | undefined;
-    taskSubType?: string | undefined;
-    problemSchemaVersion?: string | undefined;
-    problemVersion?: string | undefined;
-
-    constructor(data?: IProblemAbout) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.problemID = data["problemID"];
-            this.problemName = data["problemName"];
-            this.problemDescription = data["problemDescription"];
-            this.taskType = data["taskType"];
-            this.taskSubType = data["taskSubType"];
-            this.problemSchemaVersion = data["problemSchemaVersion"];
-            this.problemVersion = data["problemVersion"];
-        }
-    }
-
-    static fromJS(data: any): ProblemAbout {
-        data = typeof data === 'object' ? data : {};
-        let result = new ProblemAbout();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["problemID"] = this.problemID;
-        data["problemName"] = this.problemName;
-        data["problemDescription"] = this.problemDescription;
-        data["taskType"] = this.taskType;
-        data["taskSubType"] = this.taskSubType;
-        data["problemSchemaVersion"] = this.problemSchemaVersion;
-        data["problemVersion"] = this.problemVersion;
-        return data;
-    }
-}
-
-export interface IProblemAbout {
-    problemID?: string | undefined;
-    problemName?: string | undefined;
-    problemDescription?: string | undefined;
-    taskType?: string | undefined;
-    taskSubType?: string | undefined;
-    problemSchemaVersion?: string | undefined;
-    problemVersion?: string | undefined;
-}
-
-export class ProblemInputs implements IProblemInputs {
-    data?: ProblemData[] | undefined;
-    performanceMetrics?: ProblemPerformanceMetric[] | undefined;
-
-    constructor(data?: IProblemInputs) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            if (data["data"] && data["data"].constructor === Array) {
-                this.data = [];
-                for (let item of data["data"])
-                    this.data.push(ProblemData.fromJS(item));
-            }
-            if (data["performanceMetrics"] && data["performanceMetrics"].constructor === Array) {
-                this.performanceMetrics = [];
-                for (let item of data["performanceMetrics"])
-                    this.performanceMetrics.push(ProblemPerformanceMetric.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): ProblemInputs {
-        data = typeof data === 'object' ? data : {};
-        let result = new ProblemInputs();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.data && this.data.constructor === Array) {
-            data["data"] = [];
-            for (let item of this.data)
-                data["data"].push(item.toJSON());
-        }
-        if (this.performanceMetrics && this.performanceMetrics.constructor === Array) {
-            data["performanceMetrics"] = [];
-            for (let item of this.performanceMetrics)
-                data["performanceMetrics"].push(item.toJSON());
-        }
-        return data;
-    }
-}
-
-export interface IProblemInputs {
-    data?: ProblemData[] | undefined;
-    performanceMetrics?: ProblemPerformanceMetric[] | undefined;
-}
-
-export class ProblemData implements IProblemData {
-    datasetID?: string | undefined;
-    targets?: ProblemTarget[] | undefined;
-
-    constructor(data?: IProblemData) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.datasetID = data["datasetID"];
-            if (data["targets"] && data["targets"].constructor === Array) {
-                this.targets = [];
-                for (let item of data["targets"])
-                    this.targets.push(ProblemTarget.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): ProblemData {
-        data = typeof data === 'object' ? data : {};
-        let result = new ProblemData();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["datasetID"] = this.datasetID;
-        if (this.targets && this.targets.constructor === Array) {
-            data["targets"] = [];
-            for (let item of this.targets)
-                data["targets"].push(item.toJSON());
-        }
-        return data;
-    }
-}
-
-export interface IProblemData {
-    datasetID?: string | undefined;
-    targets?: ProblemTarget[] | undefined;
-}
-
-export class ProblemTarget implements IProblemTarget {
-    targetIndex?: number | undefined;
-    resID?: string | undefined;
-    colIndex?: number | undefined;
-    colName?: string | undefined;
-
-    constructor(data?: IProblemTarget) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.targetIndex = data["targetIndex"];
-            this.resID = data["resID"];
-            this.colIndex = data["colIndex"];
-            this.colName = data["colName"];
-        }
-    }
-
-    static fromJS(data: any): ProblemTarget {
-        data = typeof data === 'object' ? data : {};
-        let result = new ProblemTarget();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["targetIndex"] = this.targetIndex;
-        data["resID"] = this.resID;
-        data["colIndex"] = this.colIndex;
-        data["colName"] = this.colName;
-        return data;
-    }
-}
-
-export interface IProblemTarget {
-    targetIndex?: number | undefined;
-    resID?: string | undefined;
-    colIndex?: number | undefined;
-    colName?: string | undefined;
-}
-
-export class ProblemPerformanceMetric implements IProblemPerformanceMetric {
-    metric?: string | undefined;
-
-    constructor(data?: IProblemPerformanceMetric) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.metric = data["metric"];
-        }
-    }
-
-    static fromJS(data: any): ProblemPerformanceMetric {
-        data = typeof data === 'object' ? data : {};
-        let result = new ProblemPerformanceMetric();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["metric"] = this.metric;
-        return data;
-    }
-}
-
-export interface IProblemPerformanceMetric {
-    metric?: string | undefined;
-}
-
-export class DarpaDatasetDoc implements IDarpaDatasetDoc {
-    about?: DatasetAbout | undefined;
-    dataResources?: Resource[] | undefined;
-
-    constructor(data?: IDarpaDatasetDoc) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.about = data["about"] ? DatasetAbout.fromJS(data["about"]) : <any>undefined;
-            if (data["dataResources"] && data["dataResources"].constructor === Array) {
-                this.dataResources = [];
-                for (let item of data["dataResources"])
-                    this.dataResources.push(Resource.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): DarpaDatasetDoc {
-        data = typeof data === 'object' ? data : {};
-        let result = new DarpaDatasetDoc();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["about"] = this.about ? this.about.toJSON() : <any>undefined;
-        if (this.dataResources && this.dataResources.constructor === Array) {
-            data["dataResources"] = [];
-            for (let item of this.dataResources)
-                data["dataResources"].push(item.toJSON());
-        }
-        return data;
-    }
-}
-
-export interface IDarpaDatasetDoc {
-    about?: DatasetAbout | undefined;
-    dataResources?: Resource[] | undefined;
-}
-
-export class DatasetAbout implements IDatasetAbout {
-    datasetID?: string | undefined;
-    datasetName?: string | undefined;
-    description?: string | undefined;
-    citation?: string | undefined;
-    license?: string | undefined;
-    source?: string | undefined;
-    sourceURI?: string | undefined;
-    approximateSize?: string | undefined;
-    datasetSchemaVersion?: string | undefined;
-    redacted?: boolean | undefined;
-    datasetVersion?: string | undefined;
-
-    constructor(data?: IDatasetAbout) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.datasetID = data["datasetID"];
-            this.datasetName = data["datasetName"];
-            this.description = data["description"];
-            this.citation = data["citation"];
-            this.license = data["license"];
-            this.source = data["source"];
-            this.sourceURI = data["sourceURI"];
-            this.approximateSize = data["approximateSize"];
-            this.datasetSchemaVersion = data["datasetSchemaVersion"];
-            this.redacted = data["redacted"];
-            this.datasetVersion = data["datasetVersion"];
-        }
-    }
-
-    static fromJS(data: any): DatasetAbout {
-        data = typeof data === 'object' ? data : {};
-        let result = new DatasetAbout();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["datasetID"] = this.datasetID;
-        data["datasetName"] = this.datasetName;
-        data["description"] = this.description;
-        data["citation"] = this.citation;
-        data["license"] = this.license;
-        data["source"] = this.source;
-        data["sourceURI"] = this.sourceURI;
-        data["approximateSize"] = this.approximateSize;
-        data["datasetSchemaVersion"] = this.datasetSchemaVersion;
-        data["redacted"] = this.redacted;
-        data["datasetVersion"] = this.datasetVersion;
-        return data;
-    }
-}
-
-export interface IDatasetAbout {
-    datasetID?: string | undefined;
-    datasetName?: string | undefined;
-    description?: string | undefined;
-    citation?: string | undefined;
-    license?: string | undefined;
-    source?: string | undefined;
-    sourceURI?: string | undefined;
-    approximateSize?: string | undefined;
-    datasetSchemaVersion?: string | undefined;
-    redacted?: boolean | undefined;
-    datasetVersion?: string | undefined;
-}
-
-export class Resource implements IResource {
-    resID?: string | undefined;
-    resPath?: string | undefined;
-    resType?: string | undefined;
-    resFormat?: string[] | undefined;
-    columns?: Column[] | undefined;
-    isCollection?: boolean | undefined;
-
-    constructor(data?: IResource) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.resID = data["resID"];
-            this.resPath = data["resPath"];
-            this.resType = data["resType"];
-            if (data["resFormat"] && data["resFormat"].constructor === Array) {
-                this.resFormat = [];
-                for (let item of data["resFormat"])
-                    this.resFormat.push(item);
-            }
-            if (data["columns"] && data["columns"].constructor === Array) {
-                this.columns = [];
-                for (let item of data["columns"])
-                    this.columns.push(Column.fromJS(item));
-            }
-            this.isCollection = data["isCollection"];
-        }
-    }
-
-    static fromJS(data: any): Resource {
-        data = typeof data === 'object' ? data : {};
-        let result = new Resource();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["resID"] = this.resID;
-        data["resPath"] = this.resPath;
-        data["resType"] = this.resType;
-        if (this.resFormat && this.resFormat.constructor === Array) {
-            data["resFormat"] = [];
-            for (let item of this.resFormat)
-                data["resFormat"].push(item);
-        }
-        if (this.columns && this.columns.constructor === Array) {
-            data["columns"] = [];
-            for (let item of this.columns)
-                data["columns"].push(item.toJSON());
-        }
-        data["isCollection"] = this.isCollection;
-        return data;
-    }
-}
-
-export interface IResource {
-    resID?: string | undefined;
-    resPath?: string | undefined;
-    resType?: string | undefined;
-    resFormat?: string[] | undefined;
-    columns?: Column[] | undefined;
-    isCollection?: boolean | undefined;
-}
-
-export class Column implements IColumn {
-    colIndex?: number | undefined;
-    colDescription?: string | undefined;
-    colName?: string | undefined;
-    colType?: string | undefined;
-    role?: string[] | undefined;
-    refersTo?: Reference | undefined;
-
-    constructor(data?: IColumn) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.colIndex = data["colIndex"];
-            this.colDescription = data["colDescription"];
-            this.colName = data["colName"];
-            this.colType = data["colType"];
-            if (data["role"] && data["role"].constructor === Array) {
-                this.role = [];
-                for (let item of data["role"])
-                    this.role.push(item);
-            }
-            this.refersTo = data["refersTo"] ? Reference.fromJS(data["refersTo"]) : <any>undefined;
-        }
-    }
-
-    static fromJS(data: any): Column {
-        data = typeof data === 'object' ? data : {};
-        let result = new Column();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["colIndex"] = this.colIndex;
-        data["colDescription"] = this.colDescription;
-        data["colName"] = this.colName;
-        data["colType"] = this.colType;
-        if (this.role && this.role.constructor === Array) {
-            data["role"] = [];
-            for (let item of this.role)
-                data["role"].push(item);
-        }
-        data["refersTo"] = this.refersTo ? this.refersTo.toJSON() : <any>undefined;
-        return data;
-    }
-}
-
-export interface IColumn {
-    colIndex?: number | undefined;
-    colDescription?: string | undefined;
-    colName?: string | undefined;
-    colType?: string | undefined;
-    role?: string[] | undefined;
-    refersTo?: Reference | undefined;
-}
-
-export class Reference implements IReference {
-    resID?: string | undefined;
-
-    constructor(data?: IReference) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.resID = data["resID"];
-        }
-    }
-
-    static fromJS(data: any): Reference {
-        data = typeof data === 'object' ? data : {};
-        let result = new Reference();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["resID"] = this.resID;
-        return data;
-    }
-}
-
-export interface IReference {
-    resID?: string | undefined;
-}
-
-export class ProblemFinderRows implements IProblemFinderRows {
-    label?: string | undefined;
-    type?: string | undefined;
-    features?: Feature[] | undefined;
-
-    constructor(data?: IProblemFinderRows) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.label = data["label"];
-            this.type = data["type"];
-            if (data["features"] && data["features"].constructor === Array) {
-                this.features = [];
-                for (let item of data["features"])
-                    this.features.push(Feature.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): ProblemFinderRows {
-        data = typeof data === 'object' ? data : {};
-        let result = new ProblemFinderRows();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["label"] = this.label;
-        data["type"] = this.type;
-        if (this.features && this.features.constructor === Array) {
-            data["features"] = [];
-            for (let item of this.features)
-                data["features"].push(item.toJSON());
-        }
-        return data;
-    }
-}
-
-export interface IProblemFinderRows {
-    label?: string | undefined;
-    type?: string | undefined;
-    features?: Feature[] | undefined;
-}
-
-export class Feature implements IFeature {
-    name?: string | undefined;
-    selected?: boolean | undefined;
-    value?: number | undefined;
-
-    constructor(data?: IFeature) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.name = data["name"];
-            this.selected = data["selected"];
-            this.value = data["value"];
-        }
-    }
-
-    static fromJS(data: any): Feature {
-        data = typeof data === 'object' ? data : {};
-        let result = new Feature();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["name"] = this.name;
-        data["selected"] = this.selected;
-        data["value"] = this.value;
-        return data;
-    }
-}
-
-export interface IFeature {
-    name?: string | undefined;
-    selected?: boolean | undefined;
-    value?: number | undefined;
-}
-
-export enum DataType2 {
-    Int = 0,
-    String = 1,
-    Float = 2,
-    Double = 3,
-    DateTime = 4,
-    Object = 5,
-    Undefined = 6,
-}
-
-export abstract class DataTypeExtensions implements IDataTypeExtensions {
-
-    constructor(data?: IDataTypeExtensions) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): DataTypeExtensions {
-        data = typeof data === 'object' ? data : {};
-        throw new Error("The abstract class 'DataTypeExtensions' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        return data;
-    }
-}
-
-export interface IDataTypeExtensions {
-}
-
-export class ResObject implements IResObject {
-    columnName?: string | undefined;
-
-    constructor(data?: IResObject) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.columnName = data["columnName"];
-        }
-    }
-
-    static fromJS(data: any): ResObject {
-        data = typeof data === 'object' ? data : {};
-        let result = new ResObject();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["columnName"] = this.columnName;
-        return data;
-    }
-}
-
-export interface IResObject {
-    columnName?: string | undefined;
-}
-
-export class Exception implements IException {
-    message?: string | undefined;
-    innerException?: Exception | undefined;
-    stackTrace?: string | undefined;
-    source?: string | undefined;
-
-    constructor(data?: IException) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.message = data["Message"];
-            this.innerException = data["InnerException"] ? Exception.fromJS(data["InnerException"]) : <any>undefined;
-            this.stackTrace = data["StackTrace"];
-            this.source = data["Source"];
-        }
-    }
-
-    static fromJS(data: any): Exception {
-        data = typeof data === 'object' ? data : {};
-        let result = new Exception();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Message"] = this.message;
-        data["InnerException"] = this.innerException ? this.innerException.toJSON() : <any>undefined;
-        data["StackTrace"] = this.stackTrace;
-        data["Source"] = this.source;
-        return data;
-    }
-}
-
-export interface IException {
-    message?: string | undefined;
-    innerException?: Exception | undefined;
-    stackTrace?: string | undefined;
-    source?: string | undefined;
-}
-
-export class IDEAException extends Exception implements IIDEAException {
-
-    constructor(data?: IIDEAException) {
-        super(data);
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): IDEAException {
-        data = typeof data === 'object' ? data : {};
-        let result = new IDEAException();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IIDEAException extends IException {
-}
-
-export class CodeParameters implements ICodeParameters {
-    attributeCodeParameters?: AttributeCodeParameters[] | undefined;
-    adapterName?: string | undefined;
-
-    constructor(data?: ICodeParameters) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            if (data["AttributeCodeParameters"] && data["AttributeCodeParameters"].constructor === Array) {
-                this.attributeCodeParameters = [];
-                for (let item of data["AttributeCodeParameters"])
-                    this.attributeCodeParameters.push(AttributeCodeParameters.fromJS(item));
-            }
-            this.adapterName = data["AdapterName"];
-        }
-    }
-
-    static fromJS(data: any): CodeParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new CodeParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.attributeCodeParameters && this.attributeCodeParameters.constructor === Array) {
-            data["AttributeCodeParameters"] = [];
-            for (let item of this.attributeCodeParameters)
-                data["AttributeCodeParameters"].push(item.toJSON());
-        }
-        data["AdapterName"] = this.adapterName;
-        return data;
-    }
-}
-
-export interface ICodeParameters {
-    attributeCodeParameters?: AttributeCodeParameters[] | undefined;
-    adapterName?: string | undefined;
-}
-
-export class CompileResult implements ICompileResult {
-    compileSuccess?: boolean | undefined;
-    compileMessage?: string | undefined;
-    dataType?: DataType | undefined;
-    replaceAttributeParameters?: AttributeParameters[] | undefined;
-
-    constructor(data?: ICompileResult) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.compileSuccess = data["CompileSuccess"];
-            this.compileMessage = data["CompileMessage"];
-            this.dataType = data["DataType"];
-            if (data["ReplaceAttributeParameters"] && data["ReplaceAttributeParameters"].constructor === Array) {
-                this.replaceAttributeParameters = [];
-                for (let item of data["ReplaceAttributeParameters"])
-                    this.replaceAttributeParameters.push(AttributeParameters.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): CompileResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new CompileResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["CompileSuccess"] = this.compileSuccess;
-        data["CompileMessage"] = this.compileMessage;
-        data["DataType"] = this.dataType;
-        if (this.replaceAttributeParameters && this.replaceAttributeParameters.constructor === Array) {
-            data["ReplaceAttributeParameters"] = [];
-            for (let item of this.replaceAttributeParameters)
-                data["ReplaceAttributeParameters"].push(item.toJSON());
-        }
-        return data;
-    }
-}
-
-export interface ICompileResult {
-    compileSuccess?: boolean | undefined;
-    compileMessage?: string | undefined;
-    dataType?: DataType | undefined;
-    replaceAttributeParameters?: AttributeParameters[] | undefined;
-}
-
-export class CompileResults implements ICompileResults {
-    rawNameToCompileResult?: { [key: string]: CompileResult; } | undefined;
-
-    constructor(data?: ICompileResults) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            if (data["RawNameToCompileResult"]) {
-                this.rawNameToCompileResult = {};
-                for (let key in data["RawNameToCompileResult"]) {
-                    if (data["RawNameToCompileResult"].hasOwnProperty(key))
-                        this.rawNameToCompileResult[key] = data["RawNameToCompileResult"][key] ? CompileResult.fromJS(data["RawNameToCompileResult"][key]) : new CompileResult();
-                }
-            }
-        }
-    }
-
-    static fromJS(data: any): CompileResults {
-        data = typeof data === 'object' ? data : {};
-        let result = new CompileResults();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.rawNameToCompileResult) {
-            data["RawNameToCompileResult"] = {};
-            for (let key in this.rawNameToCompileResult) {
-                if (this.rawNameToCompileResult.hasOwnProperty(key))
-                    data["RawNameToCompileResult"][key] = this.rawNameToCompileResult[key];
-            }
-        }
-        return data;
-    }
-}
-
-export interface ICompileResults {
-    rawNameToCompileResult?: { [key: string]: CompileResult; } | undefined;
-}
-
-export abstract class UniqueJson implements IUniqueJson {
-
-    constructor(data?: IUniqueJson) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): UniqueJson {
-        data = typeof data === 'object' ? data : {};
-        throw new Error("The abstract class 'UniqueJson' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        return data;
-    }
-}
-
-export interface IUniqueJson {
-}
-
-export abstract class OperationParameters extends UniqueJson implements IOperationParameters {
-    isCachable?: boolean | undefined;
-
-    protected _discriminator: string;
-
-    constructor(data?: IOperationParameters) {
-        super(data);
-        this._discriminator = "OperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.isCachable = data["IsCachable"];
-        }
-    }
-
-    static fromJS(data: any): OperationParameters {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "DataOperationParameters") {
-            throw new Error("The abstract class 'DataOperationParameters' cannot be instantiated.");
-        }
-        if (data["discriminator"] === "ExampleOperationParameters") {
-            let result = new ExampleOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "HistogramOperationParameters") {
-            let result = new HistogramOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "DistOperationParameters") {
-            throw new Error("The abstract class 'DistOperationParameters' cannot be instantiated.");
-        }
-        if (data["discriminator"] === "OptimizerOperationParameters") {
-            let result = new OptimizerOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "RawDataOperationParameters") {
-            let result = new RawDataOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "RecommenderOperationParameters") {
-            let result = new RecommenderOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "CDFOperationParameters") {
-            let result = new CDFOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "TestDistOperationParameters") {
-            throw new Error("The abstract class 'TestDistOperationParameters' cannot be instantiated.");
-        }
-        if (data["discriminator"] === "ChiSquaredTestOperationParameters") {
-            let result = new ChiSquaredTestOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "HypothesisTestParameters") {
-            throw new Error("The abstract class 'HypothesisTestParameters' cannot be instantiated.");
-        }
-        if (data["discriminator"] === "CorrelationTestOperationParameters") {
-            let result = new CorrelationTestOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "EmpiricalDistOperationParameters") {
-            let result = new EmpiricalDistOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "KSTestOperationParameters") {
-            let result = new KSTestOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "NewModelOperationParameters") {
-            let result = new NewModelOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "ModelOperationParameters") {
-            throw new Error("The abstract class 'ModelOperationParameters' cannot be instantiated.");
-        }
-        if (data["discriminator"] === "RootMeanSquareTestOperationParameters") {
-            let result = new RootMeanSquareTestOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "TTestOperationParameters") {
-            let result = new TTestOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "FeatureImportanceOperationParameters") {
-            let result = new FeatureImportanceOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "SampleOperationParameters") {
-            let result = new SampleOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "AddComparisonParameters") {
-            let result = new AddComparisonParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "GetModelStateParameters") {
-            let result = new GetModelStateParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "FrequentItemsetOperationParameters") {
-            let result = new FrequentItemsetOperationParameters();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'OperationParameters' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["discriminator"] = this._discriminator;
-        data["IsCachable"] = this.isCachable;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IOperationParameters extends IUniqueJson {
-    isCachable?: boolean | undefined;
-}
-
-export abstract class DataOperationParameters extends OperationParameters implements IDataOperationParameters {
-    sampleStreamBlockSize?: number | undefined;
-    adapterName?: string | undefined;
-    isCachable?: boolean | undefined;
-
-    constructor(data?: IDataOperationParameters) {
-        super(data);
-        this._discriminator = "DataOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.sampleStreamBlockSize = data["SampleStreamBlockSize"];
-            this.adapterName = data["AdapterName"];
-            this.isCachable = data["IsCachable"];
-        }
-    }
-
-    static fromJS(data: any): DataOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "ExampleOperationParameters") {
-            let result = new ExampleOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "HistogramOperationParameters") {
-            let result = new HistogramOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "DistOperationParameters") {
-            throw new Error("The abstract class 'DistOperationParameters' cannot be instantiated.");
-        }
-        if (data["discriminator"] === "OptimizerOperationParameters") {
-            let result = new OptimizerOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "RawDataOperationParameters") {
-            let result = new RawDataOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "RecommenderOperationParameters") {
-            let result = new RecommenderOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "CDFOperationParameters") {
-            let result = new CDFOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "TestDistOperationParameters") {
-            throw new Error("The abstract class 'TestDistOperationParameters' cannot be instantiated.");
-        }
-        if (data["discriminator"] === "EmpiricalDistOperationParameters") {
-            let result = new EmpiricalDistOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "FeatureImportanceOperationParameters") {
-            let result = new FeatureImportanceOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "SampleOperationParameters") {
-            let result = new SampleOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "FrequentItemsetOperationParameters") {
-            let result = new FrequentItemsetOperationParameters();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'DataOperationParameters' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["SampleStreamBlockSize"] = this.sampleStreamBlockSize;
-        data["AdapterName"] = this.adapterName;
-        data["IsCachable"] = this.isCachable;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IDataOperationParameters extends IOperationParameters {
-    sampleStreamBlockSize?: number | undefined;
-    adapterName?: string | undefined;
-    isCachable?: boolean | undefined;
-}
-
-export class ExampleOperationParameters extends DataOperationParameters implements IExampleOperationParameters {
-    filter?: string | undefined;
-    attributeParameters?: AttributeParameters[] | undefined;
-    attributeCodeParameters?: AttributeCaclculatedParameters[] | undefined;
-    dummyValue?: number | undefined;
-    exampleType?: string | undefined;
-
-    constructor(data?: IExampleOperationParameters) {
-        super(data);
-        this._discriminator = "ExampleOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.filter = data["Filter"];
-            if (data["AttributeParameters"] && data["AttributeParameters"].constructor === Array) {
-                this.attributeParameters = [];
-                for (let item of data["AttributeParameters"])
-                    this.attributeParameters.push(AttributeParameters.fromJS(item));
-            }
-            if (data["AttributeCodeParameters"] && data["AttributeCodeParameters"].constructor === Array) {
-                this.attributeCodeParameters = [];
-                for (let item of data["AttributeCodeParameters"])
-                    this.attributeCodeParameters.push(AttributeCaclculatedParameters.fromJS(item));
-            }
-            this.dummyValue = data["DummyValue"];
-            this.exampleType = data["ExampleType"];
-        }
-    }
-
-    static fromJS(data: any): ExampleOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new ExampleOperationParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Filter"] = this.filter;
-        if (this.attributeParameters && this.attributeParameters.constructor === Array) {
-            data["AttributeParameters"] = [];
-            for (let item of this.attributeParameters)
-                data["AttributeParameters"].push(item.toJSON());
-        }
-        if (this.attributeCodeParameters && this.attributeCodeParameters.constructor === Array) {
-            data["AttributeCodeParameters"] = [];
-            for (let item of this.attributeCodeParameters)
-                data["AttributeCodeParameters"].push(item.toJSON());
-        }
-        data["DummyValue"] = this.dummyValue;
-        data["ExampleType"] = this.exampleType;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IExampleOperationParameters extends IDataOperationParameters {
-    filter?: string | undefined;
-    attributeParameters?: AttributeParameters[] | undefined;
-    attributeCodeParameters?: AttributeCaclculatedParameters[] | undefined;
-    dummyValue?: number | undefined;
-    exampleType?: string | undefined;
-}
-
-export abstract class DistOperationParameters extends DataOperationParameters implements IDistOperationParameters {
-    filter?: string | undefined;
-    attributeCalculatedParameters?: AttributeCaclculatedParameters[] | undefined;
-
-    constructor(data?: IDistOperationParameters) {
-        super(data);
-        this._discriminator = "DistOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.filter = data["Filter"];
-            if (data["AttributeCalculatedParameters"] && data["AttributeCalculatedParameters"].constructor === Array) {
-                this.attributeCalculatedParameters = [];
-                for (let item of data["AttributeCalculatedParameters"])
-                    this.attributeCalculatedParameters.push(AttributeCaclculatedParameters.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): DistOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "HistogramOperationParameters") {
-            let result = new HistogramOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "OptimizerOperationParameters") {
-            let result = new OptimizerOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "RawDataOperationParameters") {
-            let result = new RawDataOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "CDFOperationParameters") {
-            let result = new CDFOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "TestDistOperationParameters") {
-            throw new Error("The abstract class 'TestDistOperationParameters' cannot be instantiated.");
-        }
-        if (data["discriminator"] === "EmpiricalDistOperationParameters") {
-            let result = new EmpiricalDistOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "FeatureImportanceOperationParameters") {
-            let result = new FeatureImportanceOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "SampleOperationParameters") {
-            let result = new SampleOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "FrequentItemsetOperationParameters") {
-            let result = new FrequentItemsetOperationParameters();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'DistOperationParameters' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Filter"] = this.filter;
-        if (this.attributeCalculatedParameters && this.attributeCalculatedParameters.constructor === Array) {
-            data["AttributeCalculatedParameters"] = [];
-            for (let item of this.attributeCalculatedParameters)
-                data["AttributeCalculatedParameters"].push(item.toJSON());
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IDistOperationParameters extends IDataOperationParameters {
-    filter?: string | undefined;
-    attributeCalculatedParameters?: AttributeCaclculatedParameters[] | undefined;
-}
-
-export class HistogramOperationParameters extends DistOperationParameters implements IHistogramOperationParameters {
-    sortPerBinAggregateParameter?: AggregateParameters | undefined;
-    binningParameters?: BinningParameters[] | undefined;
-    perBinAggregateParameters?: AggregateParameters[] | undefined;
-    globalAggregateParameters?: AggregateParameters[] | undefined;
-    brushes?: string[] | undefined;
-    enableBrushComputation?: boolean | undefined;
-    degreeOfParallism?: number | undefined;
-
-    constructor(data?: IHistogramOperationParameters) {
-        super(data);
-        this._discriminator = "HistogramOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.sortPerBinAggregateParameter = data["SortPerBinAggregateParameter"] ? AggregateParameters.fromJS(data["SortPerBinAggregateParameter"]) : <any>undefined;
-            if (data["BinningParameters"] && data["BinningParameters"].constructor === Array) {
-                this.binningParameters = [];
-                for (let item of data["BinningParameters"])
-                    this.binningParameters.push(BinningParameters.fromJS(item));
-            }
-            if (data["PerBinAggregateParameters"] && data["PerBinAggregateParameters"].constructor === Array) {
-                this.perBinAggregateParameters = [];
-                for (let item of data["PerBinAggregateParameters"])
-                    this.perBinAggregateParameters.push(AggregateParameters.fromJS(item));
-            }
-            if (data["GlobalAggregateParameters"] && data["GlobalAggregateParameters"].constructor === Array) {
-                this.globalAggregateParameters = [];
-                for (let item of data["GlobalAggregateParameters"])
-                    this.globalAggregateParameters.push(AggregateParameters.fromJS(item));
-            }
-            if (data["Brushes"] && data["Brushes"].constructor === Array) {
-                this.brushes = [];
-                for (let item of data["Brushes"])
-                    this.brushes.push(item);
-            }
-            this.enableBrushComputation = data["EnableBrushComputation"];
-            this.degreeOfParallism = data["DegreeOfParallism"];
-        }
-    }
-
-    static fromJS(data: any): HistogramOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new HistogramOperationParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["SortPerBinAggregateParameter"] = this.sortPerBinAggregateParameter ? this.sortPerBinAggregateParameter.toJSON() : <any>undefined;
-        if (this.binningParameters && this.binningParameters.constructor === Array) {
-            data["BinningParameters"] = [];
-            for (let item of this.binningParameters)
-                data["BinningParameters"].push(item.toJSON());
-        }
-        if (this.perBinAggregateParameters && this.perBinAggregateParameters.constructor === Array) {
-            data["PerBinAggregateParameters"] = [];
-            for (let item of this.perBinAggregateParameters)
-                data["PerBinAggregateParameters"].push(item.toJSON());
-        }
-        if (this.globalAggregateParameters && this.globalAggregateParameters.constructor === Array) {
-            data["GlobalAggregateParameters"] = [];
-            for (let item of this.globalAggregateParameters)
-                data["GlobalAggregateParameters"].push(item.toJSON());
-        }
-        if (this.brushes && this.brushes.constructor === Array) {
-            data["Brushes"] = [];
-            for (let item of this.brushes)
-                data["Brushes"].push(item);
-        }
-        data["EnableBrushComputation"] = this.enableBrushComputation;
-        data["DegreeOfParallism"] = this.degreeOfParallism;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IHistogramOperationParameters extends IDistOperationParameters {
-    sortPerBinAggregateParameter?: AggregateParameters | undefined;
-    binningParameters?: BinningParameters[] | undefined;
-    perBinAggregateParameters?: AggregateParameters[] | undefined;
-    globalAggregateParameters?: AggregateParameters[] | undefined;
-    brushes?: string[] | undefined;
-    enableBrushComputation?: boolean | undefined;
-    degreeOfParallism?: number | undefined;
-}
-
-export class OptimizerOperationParameters extends DistOperationParameters implements IOptimizerOperationParameters {
-    taskType?: TaskType | undefined;
-    taskSubType?: TaskSubType | undefined;
-    metricType?: MetricType | undefined;
-    labelAttribute?: AttributeParameters | undefined;
-    featureAttributes?: AttributeParameters[] | undefined;
-    requiredPrimitives?: string[] | undefined;
-    pythonFilter?: string | undefined;
-    trainFilter?: string | undefined;
-    pythonTrainFilter?: string | undefined;
-    testFilter?: string | undefined;
-    pythonTestFilter?: string | undefined;
-
-    constructor(data?: IOptimizerOperationParameters) {
-        super(data);
-        this._discriminator = "OptimizerOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.taskType = data["TaskType"];
-            this.taskSubType = data["TaskSubType"];
-            this.metricType = data["MetricType"];
-            this.labelAttribute = data["LabelAttribute"] ? AttributeParameters.fromJS(data["LabelAttribute"]) : <any>undefined;
-            if (data["FeatureAttributes"] && data["FeatureAttributes"].constructor === Array) {
-                this.featureAttributes = [];
-                for (let item of data["FeatureAttributes"])
-                    this.featureAttributes.push(AttributeParameters.fromJS(item));
-            }
-            if (data["RequiredPrimitives"] && data["RequiredPrimitives"].constructor === Array) {
-                this.requiredPrimitives = [];
-                for (let item of data["RequiredPrimitives"])
-                    this.requiredPrimitives.push(item);
-            }
-            this.pythonFilter = data["PythonFilter"];
-            this.trainFilter = data["TrainFilter"];
-            this.pythonTrainFilter = data["PythonTrainFilter"];
-            this.testFilter = data["TestFilter"];
-            this.pythonTestFilter = data["PythonTestFilter"];
-        }
-    }
-
-    static fromJS(data: any): OptimizerOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new OptimizerOperationParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["TaskType"] = this.taskType;
-        data["TaskSubType"] = this.taskSubType;
-        data["MetricType"] = this.metricType;
-        data["LabelAttribute"] = this.labelAttribute ? this.labelAttribute.toJSON() : <any>undefined;
-        if (this.featureAttributes && this.featureAttributes.constructor === Array) {
-            data["FeatureAttributes"] = [];
-            for (let item of this.featureAttributes)
-                data["FeatureAttributes"].push(item.toJSON());
-        }
-        if (this.requiredPrimitives && this.requiredPrimitives.constructor === Array) {
-            data["RequiredPrimitives"] = [];
-            for (let item of this.requiredPrimitives)
-                data["RequiredPrimitives"].push(item);
-        }
-        data["PythonFilter"] = this.pythonFilter;
-        data["TrainFilter"] = this.trainFilter;
-        data["PythonTrainFilter"] = this.pythonTrainFilter;
-        data["TestFilter"] = this.testFilter;
-        data["PythonTestFilter"] = this.pythonTestFilter;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IOptimizerOperationParameters extends IDistOperationParameters {
-    taskType?: TaskType | undefined;
-    taskSubType?: TaskSubType | undefined;
-    metricType?: MetricType | undefined;
-    labelAttribute?: AttributeParameters | undefined;
-    featureAttributes?: AttributeParameters[] | undefined;
-    requiredPrimitives?: string[] | undefined;
-    pythonFilter?: string | undefined;
-    trainFilter?: string | undefined;
-    pythonTrainFilter?: string | undefined;
-    testFilter?: string | undefined;
-    pythonTestFilter?: string | undefined;
-}
-
-export enum TaskType {
-    Undefined = 0,
-    Classification = 1,
-    Regression = 2,
-    Clustering = 3,
-    LinkPrediction = 4,
-    VertexNomination = 5,
-    CommunityDetection = 6,
-    GraphClustering = 7,
-    GraphMatching = 8,
-    TimeSeriesForecasting = 9,
-    CollaborativeFiltering = 10,
-}
-
-export enum TaskSubType {
-    Undefined = 0,
-    None = 1,
-    Binary = 2,
-    Multiclass = 3,
-    Multilabel = 4,
-    Univariate = 5,
-    Multivariate = 6,
-    Overlapping = 7,
-    Nonoverlapping = 8,
-}
-
-export enum MetricType {
-    MetricUndefined = 0,
-    Accuracy = 1,
-    Precision = 2,
-    Recall = 3,
-    F1 = 4,
-    F1Micro = 5,
-    F1Macro = 6,
-    RocAuc = 7,
-    RocAucMicro = 8,
-    RocAucMacro = 9,
-    MeanSquaredError = 10,
-    RootMeanSquaredError = 11,
-    RootMeanSquaredErrorAvg = 12,
-    MeanAbsoluteError = 13,
-    RSquared = 14,
-    NormalizedMutualInformation = 15,
-    JaccardSimilarityScore = 16,
-    PrecisionAtTopK = 17,
-    ObjectDetectionAveragePrecision = 18,
-    Loss = 100,
-}
-
-export class RawDataOperationParameters extends DistOperationParameters implements IRawDataOperationParameters {
-    sortUpRawName?: string | undefined;
-    sortDownRawName?: string | undefined;
-    numRecords?: number | undefined;
-    binningParameters?: BinningParameters[] | undefined;
-    brushes?: string[] | undefined;
-    enableBrushComputation?: boolean | undefined;
-
-    constructor(data?: IRawDataOperationParameters) {
-        super(data);
-        this._discriminator = "RawDataOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.sortUpRawName = data["SortUpRawName"];
-            this.sortDownRawName = data["SortDownRawName"];
-            this.numRecords = data["NumRecords"];
-            if (data["BinningParameters"] && data["BinningParameters"].constructor === Array) {
-                this.binningParameters = [];
-                for (let item of data["BinningParameters"])
-                    this.binningParameters.push(BinningParameters.fromJS(item));
-            }
-            if (data["Brushes"] && data["Brushes"].constructor === Array) {
-                this.brushes = [];
-                for (let item of data["Brushes"])
-                    this.brushes.push(item);
-            }
-            this.enableBrushComputation = data["EnableBrushComputation"];
-        }
-    }
-
-    static fromJS(data: any): RawDataOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new RawDataOperationParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["SortUpRawName"] = this.sortUpRawName;
-        data["SortDownRawName"] = this.sortDownRawName;
-        data["NumRecords"] = this.numRecords;
-        if (this.binningParameters && this.binningParameters.constructor === Array) {
-            data["BinningParameters"] = [];
-            for (let item of this.binningParameters)
-                data["BinningParameters"].push(item.toJSON());
-        }
-        if (this.brushes && this.brushes.constructor === Array) {
-            data["Brushes"] = [];
-            for (let item of this.brushes)
-                data["Brushes"].push(item);
-        }
-        data["EnableBrushComputation"] = this.enableBrushComputation;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IRawDataOperationParameters extends IDistOperationParameters {
-    sortUpRawName?: string | undefined;
-    sortDownRawName?: string | undefined;
-    numRecords?: number | undefined;
-    binningParameters?: BinningParameters[] | undefined;
-    brushes?: string[] | undefined;
-    enableBrushComputation?: boolean | undefined;
-}
-
-export class RecommenderOperationParameters extends DataOperationParameters implements IRecommenderOperationParameters {
-    target?: HistogramOperationParameters | undefined;
-    budget?: number | undefined;
-    modelId?: ModelId | undefined;
-    includeAttributeParameters?: AttributeParameters[] | undefined;
-    excludeAttributeParameters?: AttributeParameters[] | undefined;
-    riskControlType?: RiskControlType | undefined;
-
-    constructor(data?: IRecommenderOperationParameters) {
-        super(data);
-        this._discriminator = "RecommenderOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.target = data["Target"] ? HistogramOperationParameters.fromJS(data["Target"]) : <any>undefined;
-            this.budget = data["Budget"];
-            this.modelId = data["ModelId"] ? ModelId.fromJS(data["ModelId"]) : <any>undefined;
-            if (data["IncludeAttributeParameters"] && data["IncludeAttributeParameters"].constructor === Array) {
-                this.includeAttributeParameters = [];
-                for (let item of data["IncludeAttributeParameters"])
-                    this.includeAttributeParameters.push(AttributeParameters.fromJS(item));
-            }
-            if (data["ExcludeAttributeParameters"] && data["ExcludeAttributeParameters"].constructor === Array) {
-                this.excludeAttributeParameters = [];
-                for (let item of data["ExcludeAttributeParameters"])
-                    this.excludeAttributeParameters.push(AttributeParameters.fromJS(item));
-            }
-            this.riskControlType = data["RiskControlType"];
-        }
-    }
-
-    static fromJS(data: any): RecommenderOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new RecommenderOperationParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Target"] = this.target ? this.target.toJSON() : <any>undefined;
-        data["Budget"] = this.budget;
-        data["ModelId"] = this.modelId ? this.modelId.toJSON() : <any>undefined;
-        if (this.includeAttributeParameters && this.includeAttributeParameters.constructor === Array) {
-            data["IncludeAttributeParameters"] = [];
-            for (let item of this.includeAttributeParameters)
-                data["IncludeAttributeParameters"].push(item.toJSON());
-        }
-        if (this.excludeAttributeParameters && this.excludeAttributeParameters.constructor === Array) {
-            data["ExcludeAttributeParameters"] = [];
-            for (let item of this.excludeAttributeParameters)
-                data["ExcludeAttributeParameters"].push(item.toJSON());
-        }
-        data["RiskControlType"] = this.riskControlType;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IRecommenderOperationParameters extends IDataOperationParameters {
-    target?: HistogramOperationParameters | undefined;
-    budget?: number | undefined;
-    modelId?: ModelId | undefined;
-    includeAttributeParameters?: AttributeParameters[] | undefined;
-    excludeAttributeParameters?: AttributeParameters[] | undefined;
-    riskControlType?: RiskControlType | undefined;
-}
-
-export class ModelId implements IModelId {
-    value?: string | undefined;
-
-    constructor(data?: IModelId) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.value = data["Value"];
-        }
-    }
-
-    static fromJS(data: any): ModelId {
-        data = typeof data === 'object' ? data : {};
-        let result = new ModelId();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Value"] = this.value;
-        return data;
-    }
-}
-
-export interface IModelId {
-    value?: string | undefined;
-}
-
-export enum RiskControlType {
-    PCER = 0,
-    Bonferroni = 1,
-    AdaBonferroni = 2,
-    HolmBonferroni = 3,
-    BHFDR = 4,
-    SeqFDR = 5,
-    AlphaFDR = 6,
-    BestFootForward = 7,
-    BetaFarsighted = 8,
-    BetaFarsightedWithSupport = 9,
-    GammaFixed = 10,
-    DeltaHopeful = 11,
-    EpsilonHybrid = 12,
-    EpsilonHybridWithoutSupport = 13,
-    PsiSupport = 14,
-    ZetaDynamic = 15,
-    Unknown = 16,
-}
-
-export abstract class TestDistOperationParameters extends DistOperationParameters implements ITestDistOperationParameters {
-    attributeParameters?: AttributeParameters[] | undefined;
-
-    constructor(data?: ITestDistOperationParameters) {
-        super(data);
-        this._discriminator = "TestDistOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["AttributeParameters"] && data["AttributeParameters"].constructor === Array) {
-                this.attributeParameters = [];
-                for (let item of data["AttributeParameters"])
-                    this.attributeParameters.push(AttributeParameters.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): TestDistOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "CDFOperationParameters") {
-            let result = new CDFOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "EmpiricalDistOperationParameters") {
-            let result = new EmpiricalDistOperationParameters();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'TestDistOperationParameters' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.attributeParameters && this.attributeParameters.constructor === Array) {
-            data["AttributeParameters"] = [];
-            for (let item of this.attributeParameters)
-                data["AttributeParameters"].push(item.toJSON());
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ITestDistOperationParameters extends IDistOperationParameters {
-    attributeParameters?: AttributeParameters[] | undefined;
-}
-
-export class CDFOperationParameters extends TestDistOperationParameters implements ICDFOperationParameters {
-
-    constructor(data?: ICDFOperationParameters) {
-        super(data);
-        this._discriminator = "CDFOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): CDFOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new CDFOperationParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ICDFOperationParameters extends ITestDistOperationParameters {
-}
-
-export abstract class HypothesisTestParameters extends OperationParameters implements IHypothesisTestParameters {
-    childOperationParameters?: OperationParameters[] | undefined;
-    isCachable?: boolean | undefined;
-
-    constructor(data?: IHypothesisTestParameters) {
-        super(data);
-        this._discriminator = "HypothesisTestParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["ChildOperationParameters"] && data["ChildOperationParameters"].constructor === Array) {
-                this.childOperationParameters = [];
-                for (let item of data["ChildOperationParameters"])
-                    this.childOperationParameters.push(OperationParameters.fromJS(item));
-            }
-            this.isCachable = data["IsCachable"];
-        }
-    }
-
-    static fromJS(data: any): HypothesisTestParameters {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "ChiSquaredTestOperationParameters") {
-            let result = new ChiSquaredTestOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "CorrelationTestOperationParameters") {
-            let result = new CorrelationTestOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "KSTestOperationParameters") {
-            let result = new KSTestOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "RootMeanSquareTestOperationParameters") {
-            let result = new RootMeanSquareTestOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "TTestOperationParameters") {
-            let result = new TTestOperationParameters();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'HypothesisTestParameters' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.childOperationParameters && this.childOperationParameters.constructor === Array) {
-            data["ChildOperationParameters"] = [];
-            for (let item of this.childOperationParameters)
-                data["ChildOperationParameters"].push(item.toJSON());
-        }
-        data["IsCachable"] = this.isCachable;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IHypothesisTestParameters extends IOperationParameters {
-    childOperationParameters?: OperationParameters[] | undefined;
-    isCachable?: boolean | undefined;
-}
-
-export class ChiSquaredTestOperationParameters extends HypothesisTestParameters implements IChiSquaredTestOperationParameters {
-
-    constructor(data?: IChiSquaredTestOperationParameters) {
-        super(data);
-        this._discriminator = "ChiSquaredTestOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): ChiSquaredTestOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new ChiSquaredTestOperationParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IChiSquaredTestOperationParameters extends IHypothesisTestParameters {
-}
-
-export class CorrelationTestOperationParameters extends HypothesisTestParameters implements ICorrelationTestOperationParameters {
-
-    constructor(data?: ICorrelationTestOperationParameters) {
-        super(data);
-        this._discriminator = "CorrelationTestOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): CorrelationTestOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new CorrelationTestOperationParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ICorrelationTestOperationParameters extends IHypothesisTestParameters {
-}
-
-export class SubmitProblemParameters implements ISubmitProblemParameters {
-    id?: string | undefined;
-
-    constructor(data?: ISubmitProblemParameters) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.id = data["Id"];
-        }
-    }
-
-    static fromJS(data: any): SubmitProblemParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new SubmitProblemParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Id"] = this.id;
-        return data;
-    }
-}
-
-export interface ISubmitProblemParameters {
-    id?: string | undefined;
-}
-
-export class SpecifyProblemParameters implements ISpecifyProblemParameters {
-    id?: string | undefined;
-    userComment?: string | undefined;
-    optimizerOperationParameters?: OptimizerOperationParameters | undefined;
-
-    constructor(data?: ISpecifyProblemParameters) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.id = data["Id"];
-            this.userComment = data["UserComment"];
-            this.optimizerOperationParameters = data["OptimizerOperationParameters"] ? OptimizerOperationParameters.fromJS(data["OptimizerOperationParameters"]) : <any>undefined;
-        }
-    }
-
-    static fromJS(data: any): SpecifyProblemParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new SpecifyProblemParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Id"] = this.id;
-        data["UserComment"] = this.userComment;
-        data["OptimizerOperationParameters"] = this.optimizerOperationParameters ? this.optimizerOperationParameters.toJSON() : <any>undefined;
-        return data;
-    }
-}
-
-export interface ISpecifyProblemParameters {
-    id?: string | undefined;
-    userComment?: string | undefined;
-    optimizerOperationParameters?: OptimizerOperationParameters | undefined;
-}
-
-export class EmpiricalDistOperationParameters extends TestDistOperationParameters implements IEmpiricalDistOperationParameters {
-    keepSamples?: boolean | undefined;
-
-    constructor(data?: IEmpiricalDistOperationParameters) {
-        super(data);
-        this._discriminator = "EmpiricalDistOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.keepSamples = data["KeepSamples"];
-        }
-    }
-
-    static fromJS(data: any): EmpiricalDistOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new EmpiricalDistOperationParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["KeepSamples"] = this.keepSamples;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IEmpiricalDistOperationParameters extends ITestDistOperationParameters {
-    keepSamples?: boolean | undefined;
-}
-
-export class KSTestOperationParameters extends HypothesisTestParameters implements IKSTestOperationParameters {
-
-    constructor(data?: IKSTestOperationParameters) {
-        super(data);
-        this._discriminator = "KSTestOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): KSTestOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new KSTestOperationParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IKSTestOperationParameters extends IHypothesisTestParameters {
-}
-
-export abstract class ModelOperationParameters extends OperationParameters implements IModelOperationParameters {
-
-    constructor(data?: IModelOperationParameters) {
-        super(data);
-        this._discriminator = "ModelOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): ModelOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "NewModelOperationParameters") {
-            let result = new NewModelOperationParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "AddComparisonParameters") {
-            let result = new AddComparisonParameters();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "GetModelStateParameters") {
-            let result = new GetModelStateParameters();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'ModelOperationParameters' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IModelOperationParameters extends IOperationParameters {
-}
-
-export class NewModelOperationParameters extends ModelOperationParameters implements INewModelOperationParameters {
-    riskControlTypes?: RiskControlType[] | undefined;
-    alpha?: number | undefined;
-    alphaInvestParameter?: AlphaInvestParameter | undefined;
-
-    constructor(data?: INewModelOperationParameters) {
-        super(data);
-        this._discriminator = "NewModelOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["RiskControlTypes"] && data["RiskControlTypes"].constructor === Array) {
-                this.riskControlTypes = [];
-                for (let item of data["RiskControlTypes"])
-                    this.riskControlTypes.push(item);
-            }
-            this.alpha = data["Alpha"];
-            this.alphaInvestParameter = data["AlphaInvestParameter"] ? AlphaInvestParameter.fromJS(data["AlphaInvestParameter"]) : <any>undefined;
-        }
-    }
-
-    static fromJS(data: any): NewModelOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new NewModelOperationParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.riskControlTypes && this.riskControlTypes.constructor === Array) {
-            data["RiskControlTypes"] = [];
-            for (let item of this.riskControlTypes)
-                data["RiskControlTypes"].push(item);
-        }
-        data["Alpha"] = this.alpha;
-        data["AlphaInvestParameter"] = this.alphaInvestParameter ? this.alphaInvestParameter.toJSON() : <any>undefined;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface INewModelOperationParameters extends IModelOperationParameters {
-    riskControlTypes?: RiskControlType[] | undefined;
-    alpha?: number | undefined;
-    alphaInvestParameter?: AlphaInvestParameter | undefined;
-}
-
-export class AlphaInvestParameter extends UniqueJson implements IAlphaInvestParameter {
-    beta?: number | undefined;
-    gamma?: number | undefined;
-    delta?: number | undefined;
-    epsilon?: number | undefined;
-    windowSize?: number | undefined;
-    psi?: number | undefined;
-
-    constructor(data?: IAlphaInvestParameter) {
-        super(data);
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.beta = data["Beta"];
-            this.gamma = data["Gamma"];
-            this.delta = data["Delta"];
-            this.epsilon = data["Epsilon"];
-            this.windowSize = data["WindowSize"];
-            this.psi = data["Psi"];
-        }
-    }
-
-    static fromJS(data: any): AlphaInvestParameter {
-        data = typeof data === 'object' ? data : {};
-        let result = new AlphaInvestParameter();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Beta"] = this.beta;
-        data["Gamma"] = this.gamma;
-        data["Delta"] = this.delta;
-        data["Epsilon"] = this.epsilon;
-        data["WindowSize"] = this.windowSize;
-        data["Psi"] = this.psi;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IAlphaInvestParameter extends IUniqueJson {
-    beta?: number | undefined;
-    gamma?: number | undefined;
-    delta?: number | undefined;
-    epsilon?: number | undefined;
-    windowSize?: number | undefined;
-    psi?: number | undefined;
-}
-
-export class RootMeanSquareTestOperationParameters extends HypothesisTestParameters implements IRootMeanSquareTestOperationParameters {
-    seeded?: boolean | undefined;
-    pValueConvergenceThreshold?: number | undefined;
-    maxSimulationBatchCount?: number | undefined;
-    perBatchSimulationCount?: number | undefined;
-
-    constructor(data?: IRootMeanSquareTestOperationParameters) {
-        super(data);
-        this._discriminator = "RootMeanSquareTestOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.seeded = data["Seeded"];
-            this.pValueConvergenceThreshold = data["PValueConvergenceThreshold"];
-            this.maxSimulationBatchCount = data["MaxSimulationBatchCount"];
-            this.perBatchSimulationCount = data["PerBatchSimulationCount"];
-        }
-    }
-
-    static fromJS(data: any): RootMeanSquareTestOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new RootMeanSquareTestOperationParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Seeded"] = this.seeded;
-        data["PValueConvergenceThreshold"] = this.pValueConvergenceThreshold;
-        data["MaxSimulationBatchCount"] = this.maxSimulationBatchCount;
-        data["PerBatchSimulationCount"] = this.perBatchSimulationCount;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IRootMeanSquareTestOperationParameters extends IHypothesisTestParameters {
-    seeded?: boolean | undefined;
-    pValueConvergenceThreshold?: number | undefined;
-    maxSimulationBatchCount?: number | undefined;
-    perBatchSimulationCount?: number | undefined;
-}
-
-export class TTestOperationParameters extends HypothesisTestParameters implements ITTestOperationParameters {
-
-    constructor(data?: ITTestOperationParameters) {
-        super(data);
-        this._discriminator = "TTestOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): TTestOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new TTestOperationParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ITTestOperationParameters extends IHypothesisTestParameters {
-}
-
-export enum EffectSize {
-    Small = 1,
-    Meduim = 2,
-    Large = 4,
-}
-
-export abstract class Result extends UniqueJson implements IResult {
-    progress?: number | undefined;
-
-    protected _discriminator: string;
-
-    constructor(data?: IResult) {
-        super(data);
-        this._discriminator = "Result";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.progress = data["Progress"];
-        }
-    }
-
-    static fromJS(data: any): Result {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "ErrorResult") {
-            let result = new ErrorResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "HistogramResult") {
-            let result = new HistogramResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "DistResult") {
-            throw new Error("The abstract class 'DistResult' cannot be instantiated.");
-        }
-        if (data["discriminator"] === "ModelWealthResult") {
-            let result = new ModelWealthResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "HypothesisTestResult") {
-            throw new Error("The abstract class 'HypothesisTestResult' cannot be instantiated.");
-        }
-        if (data["discriminator"] === "ModelOperationResult") {
-            throw new Error("The abstract class 'ModelOperationResult' cannot be instantiated.");
-        }
-        if (data["discriminator"] === "RecommenderResult") {
-            let result = new RecommenderResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "Decision") {
-            let result = new Decision();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "OptimizerResult") {
-            let result = new OptimizerResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "ExampleResult") {
-            let result = new ExampleResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "NewModelOperationResult") {
-            let result = new NewModelOperationResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "AddComparisonResult") {
-            let result = new AddComparisonResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "GetModelStateResult") {
-            let result = new GetModelStateResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "FeatureImportanceResult") {
-            let result = new FeatureImportanceResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "RawDataResult") {
-            let result = new RawDataResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "SampleResult") {
-            let result = new SampleResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "CDFResult") {
-            let result = new CDFResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "ChiSquaredTestResult") {
-            let result = new ChiSquaredTestResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "CorrelationTestResult") {
-            let result = new CorrelationTestResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "EmpiricalDistResult") {
-            let result = new EmpiricalDistResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "KSTestResult") {
-            let result = new KSTestResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "RootMeanSquareTestResult") {
-            let result = new RootMeanSquareTestResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "TTestResult") {
-            let result = new TTestResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "FrequentItemsetResult") {
-            let result = new FrequentItemsetResult();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'Result' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["discriminator"] = this._discriminator;
-        data["Progress"] = this.progress;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IResult extends IUniqueJson {
-    progress?: number | undefined;
-}
-
-export class ErrorResult extends Result implements IErrorResult {
-    message?: string | undefined;
-
-    constructor(data?: IErrorResult) {
-        super(data);
-        this._discriminator = "ErrorResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.message = data["Message"];
-        }
-    }
-
-    static fromJS(data: any): ErrorResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new ErrorResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Message"] = this.message;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IErrorResult extends IResult {
-    message?: string | undefined;
-}
-
-export abstract class DistResult extends Result implements IDistResult {
-    sampleSize?: number | undefined;
-    populationSize?: number | undefined;
-
-    constructor(data?: IDistResult) {
-        super(data);
-        this._discriminator = "DistResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.sampleSize = data["SampleSize"];
-            this.populationSize = data["PopulationSize"];
-        }
-    }
-
-    static fromJS(data: any): DistResult {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "HistogramResult") {
-            let result = new HistogramResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "RawDataResult") {
-            let result = new RawDataResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "SampleResult") {
-            let result = new SampleResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "CDFResult") {
-            let result = new CDFResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "EmpiricalDistResult") {
-            let result = new EmpiricalDistResult();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'DistResult' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["SampleSize"] = this.sampleSize;
-        data["PopulationSize"] = this.populationSize;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IDistResult extends IResult {
-    sampleSize?: number | undefined;
-    populationSize?: number | undefined;
-}
-
-export class HistogramResult extends DistResult implements IHistogramResult {
-    aggregateResults?: AggregateResult[][] | undefined;
-    isEmpty?: boolean | undefined;
-    brushes?: Brush[] | undefined;
-    binRanges?: BinRange[] | undefined;
-    aggregateParameters?: AggregateParameters[] | undefined;
-    nullValueCount?: number | undefined;
-    bins?: { [key: string]: Bin; } | undefined;
-
-    constructor(data?: IHistogramResult) {
-        super(data);
-        this._discriminator = "HistogramResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["AggregateResults"] && data["AggregateResults"].constructor === Array) {
-                this.aggregateResults = [];
-                for (let item of data["AggregateResults"])
-                    this.aggregateResults.push(item);
-            }
-            this.isEmpty = data["IsEmpty"];
-            if (data["Brushes"] && data["Brushes"].constructor === Array) {
-                this.brushes = [];
-                for (let item of data["Brushes"])
-                    this.brushes.push(Brush.fromJS(item));
-            }
-            if (data["BinRanges"] && data["BinRanges"].constructor === Array) {
-                this.binRanges = [];
-                for (let item of data["BinRanges"])
-                    this.binRanges.push(BinRange.fromJS(item));
-            }
-            if (data["AggregateParameters"] && data["AggregateParameters"].constructor === Array) {
-                this.aggregateParameters = [];
-                for (let item of data["AggregateParameters"])
-                    this.aggregateParameters.push(AggregateParameters.fromJS(item));
-            }
-            this.nullValueCount = data["NullValueCount"];
-            if (data["Bins"]) {
-                this.bins = {};
-                for (let key in data["Bins"]) {
-                    if (data["Bins"].hasOwnProperty(key))
-                        this.bins[key] = data["Bins"][key] ? Bin.fromJS(data["Bins"][key]) : new Bin();
-                }
-            }
-        }
-    }
-
-    static fromJS(data: any): HistogramResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new HistogramResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.aggregateResults && this.aggregateResults.constructor === Array) {
-            data["AggregateResults"] = [];
-            for (let item of this.aggregateResults)
-                data["AggregateResults"].push(item);
-        }
-        data["IsEmpty"] = this.isEmpty;
-        if (this.brushes && this.brushes.constructor === Array) {
-            data["Brushes"] = [];
-            for (let item of this.brushes)
-                data["Brushes"].push(item.toJSON());
-        }
-        if (this.binRanges && this.binRanges.constructor === Array) {
-            data["BinRanges"] = [];
-            for (let item of this.binRanges)
-                data["BinRanges"].push(item.toJSON());
-        }
-        if (this.aggregateParameters && this.aggregateParameters.constructor === Array) {
-            data["AggregateParameters"] = [];
-            for (let item of this.aggregateParameters)
-                data["AggregateParameters"].push(item.toJSON());
-        }
-        data["NullValueCount"] = this.nullValueCount;
-        if (this.bins) {
-            data["Bins"] = {};
-            for (let key in this.bins) {
-                if (this.bins.hasOwnProperty(key))
-                    data["Bins"][key] = this.bins[key];
-            }
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IHistogramResult extends IDistResult {
-    aggregateResults?: AggregateResult[][] | undefined;
-    isEmpty?: boolean | undefined;
-    brushes?: Brush[] | undefined;
-    binRanges?: BinRange[] | undefined;
-    aggregateParameters?: AggregateParameters[] | undefined;
-    nullValueCount?: number | undefined;
-    bins?: { [key: string]: Bin; } | undefined;
-}
-
-export abstract class AggregateResult implements IAggregateResult {
-    hasResult?: boolean | undefined;
-    n?: number | undefined;
-
-    protected _discriminator: string;
-
-    constructor(data?: IAggregateResult) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-        this._discriminator = "AggregateResult";
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.hasResult = data["HasResult"];
-            this.n = data["N"];
-        }
-    }
-
-    static fromJS(data: any): AggregateResult | undefined {
-        if (data === null || data === undefined) {
-            return undefined;
-        }
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "MarginAggregateResult") {
-            let result = new MarginAggregateResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "DoubleValueAggregateResult") {
-            let result = new DoubleValueAggregateResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "PointsAggregateResult") {
-            let result = new PointsAggregateResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "SumEstimationAggregateResult") {
-            let result = new SumEstimationAggregateResult();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'AggregateResult' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["discriminator"] = this._discriminator;
-        data["HasResult"] = this.hasResult;
-        data["N"] = this.n;
-        return data;
-    }
-}
-
-export interface IAggregateResult {
-    hasResult?: boolean | undefined;
-    n?: number | undefined;
-}
-
-export class MarginAggregateResult extends AggregateResult implements IMarginAggregateResult {
-    margin?: number | undefined;
-    absolutMargin?: number | undefined;
-    sumOfSquare?: number | undefined;
-    sampleStandardDeviation?: number | undefined;
-    mean?: number | undefined;
-    ex?: number | undefined;
-    ex2?: number | undefined;
-    variance?: number | undefined;
-
-    constructor(data?: IMarginAggregateResult) {
-        super(data);
-        this._discriminator = "MarginAggregateResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.margin = data["Margin"];
-            this.absolutMargin = data["AbsolutMargin"];
-            this.sumOfSquare = data["SumOfSquare"];
-            this.sampleStandardDeviation = data["SampleStandardDeviation"];
-            this.mean = data["Mean"];
-            this.ex = data["Ex"];
-            this.ex2 = data["Ex2"];
-            this.variance = data["Variance"];
-        }
-    }
-
-    static fromJS(data: any): MarginAggregateResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new MarginAggregateResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Margin"] = this.margin;
-        data["AbsolutMargin"] = this.absolutMargin;
-        data["SumOfSquare"] = this.sumOfSquare;
-        data["SampleStandardDeviation"] = this.sampleStandardDeviation;
-        data["Mean"] = this.mean;
-        data["Ex"] = this.ex;
-        data["Ex2"] = this.ex2;
-        data["Variance"] = this.variance;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IMarginAggregateResult extends IAggregateResult {
-    margin?: number | undefined;
-    absolutMargin?: number | undefined;
-    sumOfSquare?: number | undefined;
-    sampleStandardDeviation?: number | undefined;
-    mean?: number | undefined;
-    ex?: number | undefined;
-    ex2?: number | undefined;
-    variance?: number | undefined;
-}
-
-export class DoubleValueAggregateResult extends AggregateResult implements IDoubleValueAggregateResult {
-    result?: number | undefined;
-    temporaryResult?: number | undefined;
-
-    constructor(data?: IDoubleValueAggregateResult) {
-        super(data);
-        this._discriminator = "DoubleValueAggregateResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.result = data["Result"];
-            this.temporaryResult = data["TemporaryResult"];
-        }
-    }
-
-    static fromJS(data: any): DoubleValueAggregateResult {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "SumEstimationAggregateResult") {
-            let result = new SumEstimationAggregateResult();
-            result.init(data);
-            return result;
-        }
-        let result = new DoubleValueAggregateResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Result"] = this.result;
-        data["TemporaryResult"] = this.temporaryResult;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IDoubleValueAggregateResult extends IAggregateResult {
-    result?: number | undefined;
-    temporaryResult?: number | undefined;
-}
-
-export class PointsAggregateResult extends AggregateResult implements IPointsAggregateResult {
-    points?: Point[] | undefined;
-
-    constructor(data?: IPointsAggregateResult) {
-        super(data);
-        this._discriminator = "PointsAggregateResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["Points"] && data["Points"].constructor === Array) {
-                this.points = [];
-                for (let item of data["Points"])
-                    this.points.push(Point.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): PointsAggregateResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new PointsAggregateResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.points && this.points.constructor === Array) {
-            data["Points"] = [];
-            for (let item of this.points)
-                data["Points"].push(item.toJSON());
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IPointsAggregateResult extends IAggregateResult {
-    points?: Point[] | undefined;
-}
-
-export class Point implements IPoint {
-    x?: number | undefined;
-    y?: number | undefined;
-
-    constructor(data?: IPoint) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.x = data["X"];
-            this.y = data["Y"];
-        }
-    }
-
-    static fromJS(data: any): Point {
-        data = typeof data === 'object' ? data : {};
-        let result = new Point();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["X"] = this.x;
-        data["Y"] = this.y;
-        return data;
-    }
-}
-
-export interface IPoint {
-    x?: number | undefined;
-    y?: number | undefined;
-}
-
-export class SumEstimationAggregateResult extends DoubleValueAggregateResult implements ISumEstimationAggregateResult {
-    sum?: number | undefined;
-    sumEstimation?: number | undefined;
-
-    constructor(data?: ISumEstimationAggregateResult) {
-        super(data);
-        this._discriminator = "SumEstimationAggregateResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.sum = data["Sum"];
-            this.sumEstimation = data["SumEstimation"];
-        }
-    }
-
-    static fromJS(data: any): SumEstimationAggregateResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new SumEstimationAggregateResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Sum"] = this.sum;
-        data["SumEstimation"] = this.sumEstimation;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ISumEstimationAggregateResult extends IDoubleValueAggregateResult {
-    sum?: number | undefined;
-    sumEstimation?: number | undefined;
-}
-
-export class Brush implements IBrush {
-    brushIndex?: number | undefined;
-    brushEnum?: BrushEnum | undefined;
-
-    constructor(data?: IBrush) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.brushIndex = data["BrushIndex"];
-            this.brushEnum = data["BrushEnum"];
-        }
-    }
-
-    static fromJS(data: any): Brush {
-        data = typeof data === 'object' ? data : {};
-        let result = new Brush();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["BrushIndex"] = this.brushIndex;
-        data["BrushEnum"] = this.brushEnum;
-        return data;
-    }
-}
-
-export interface IBrush {
-    brushIndex?: number | undefined;
-    brushEnum?: BrushEnum | undefined;
-}
-
-export enum BrushEnum {
-    Overlap = 0,
-    Rest = 1,
-    All = 2,
-    UserSpecified = 3,
-}
-
-export abstract class BinRange implements IBinRange {
-    minValue?: number | undefined;
-    maxValue?: number | undefined;
-    targetBinNumber?: number | undefined;
-
-    protected _discriminator: string;
-
-    constructor(data?: IBinRange) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-        this._discriminator = "BinRange";
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.minValue = data["MinValue"];
-            this.maxValue = data["MaxValue"];
-            this.targetBinNumber = data["TargetBinNumber"];
-        }
-    }
-
-    static fromJS(data: any): BinRange {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "NominalBinRange") {
-            let result = new NominalBinRange();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "QuantitativeBinRange") {
-            let result = new QuantitativeBinRange();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "AggregateBinRange") {
-            let result = new AggregateBinRange();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "AlphabeticBinRange") {
-            let result = new AlphabeticBinRange();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "DateTimeBinRange") {
-            let result = new DateTimeBinRange();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'BinRange' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["discriminator"] = this._discriminator;
-        data["MinValue"] = this.minValue;
-        data["MaxValue"] = this.maxValue;
-        data["TargetBinNumber"] = this.targetBinNumber;
-        return data;
-    }
-}
-
-export interface IBinRange {
-    minValue?: number | undefined;
-    maxValue?: number | undefined;
-    targetBinNumber?: number | undefined;
-}
-
-export class NominalBinRange extends BinRange implements INominalBinRange {
-    labelsValue?: { [key: string]: number; } | undefined;
-    valuesLabel?: { [key: string]: string; } | undefined;
-
-    constructor(data?: INominalBinRange) {
-        super(data);
-        this._discriminator = "NominalBinRange";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["LabelsValue"]) {
-                this.labelsValue = {};
-                for (let key in data["LabelsValue"]) {
-                    if (data["LabelsValue"].hasOwnProperty(key))
-                        this.labelsValue[key] = data["LabelsValue"][key];
-                }
-            }
-            if (data["ValuesLabel"]) {
-                this.valuesLabel = {};
-                for (let key in data["ValuesLabel"]) {
-                    if (data["ValuesLabel"].hasOwnProperty(key))
-                        this.valuesLabel[key] = data["ValuesLabel"][key];
-                }
-            }
-        }
-    }
-
-    static fromJS(data: any): NominalBinRange {
-        data = typeof data === 'object' ? data : {};
-        let result = new NominalBinRange();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.labelsValue) {
-            data["LabelsValue"] = {};
-            for (let key in this.labelsValue) {
-                if (this.labelsValue.hasOwnProperty(key))
-                    data["LabelsValue"][key] = this.labelsValue[key];
-            }
-        }
-        if (this.valuesLabel) {
-            data["ValuesLabel"] = {};
-            for (let key in this.valuesLabel) {
-                if (this.valuesLabel.hasOwnProperty(key))
-                    data["ValuesLabel"][key] = this.valuesLabel[key];
-            }
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface INominalBinRange extends IBinRange {
-    labelsValue?: { [key: string]: number; } | undefined;
-    valuesLabel?: { [key: string]: string; } | undefined;
-}
-
-export class QuantitativeBinRange extends BinRange implements IQuantitativeBinRange {
-    isIntegerRange?: boolean | undefined;
-    step?: number | undefined;
-
-    constructor(data?: IQuantitativeBinRange) {
-        super(data);
-        this._discriminator = "QuantitativeBinRange";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.isIntegerRange = data["IsIntegerRange"];
-            this.step = data["Step"];
-        }
-    }
-
-    static fromJS(data: any): QuantitativeBinRange {
-        data = typeof data === 'object' ? data : {};
-        let result = new QuantitativeBinRange();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["IsIntegerRange"] = this.isIntegerRange;
-        data["Step"] = this.step;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IQuantitativeBinRange extends IBinRange {
-    isIntegerRange?: boolean | undefined;
-    step?: number | undefined;
-}
-
-export class AggregateBinRange extends BinRange implements IAggregateBinRange {
-
-    constructor(data?: IAggregateBinRange) {
-        super(data);
-        this._discriminator = "AggregateBinRange";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): AggregateBinRange {
-        data = typeof data === 'object' ? data : {};
-        let result = new AggregateBinRange();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IAggregateBinRange extends IBinRange {
-}
-
-export class AlphabeticBinRange extends BinRange implements IAlphabeticBinRange {
-    prefix?: string | undefined;
-    labelsValue?: { [key: string]: number; } | undefined;
-    valuesLabel?: { [key: string]: string; } | undefined;
-
-    constructor(data?: IAlphabeticBinRange) {
-        super(data);
-        this._discriminator = "AlphabeticBinRange";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.prefix = data["Prefix"];
-            if (data["LabelsValue"]) {
-                this.labelsValue = {};
-                for (let key in data["LabelsValue"]) {
-                    if (data["LabelsValue"].hasOwnProperty(key))
-                        this.labelsValue[key] = data["LabelsValue"][key];
-                }
-            }
-            if (data["ValuesLabel"]) {
-                this.valuesLabel = {};
-                for (let key in data["ValuesLabel"]) {
-                    if (data["ValuesLabel"].hasOwnProperty(key))
-                        this.valuesLabel[key] = data["ValuesLabel"][key];
-                }
-            }
-        }
-    }
-
-    static fromJS(data: any): AlphabeticBinRange {
-        data = typeof data === 'object' ? data : {};
-        let result = new AlphabeticBinRange();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Prefix"] = this.prefix;
-        if (this.labelsValue) {
-            data["LabelsValue"] = {};
-            for (let key in this.labelsValue) {
-                if (this.labelsValue.hasOwnProperty(key))
-                    data["LabelsValue"][key] = this.labelsValue[key];
-            }
-        }
-        if (this.valuesLabel) {
-            data["ValuesLabel"] = {};
-            for (let key in this.valuesLabel) {
-                if (this.valuesLabel.hasOwnProperty(key))
-                    data["ValuesLabel"][key] = this.valuesLabel[key];
-            }
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IAlphabeticBinRange extends IBinRange {
-    prefix?: string | undefined;
-    labelsValue?: { [key: string]: number; } | undefined;
-    valuesLabel?: { [key: string]: string; } | undefined;
-}
-
-export class DateTimeBinRange extends BinRange implements IDateTimeBinRange {
-    step?: DateTimeStep | undefined;
-
-    constructor(data?: IDateTimeBinRange) {
-        super(data);
-        this._discriminator = "DateTimeBinRange";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.step = data["Step"] ? DateTimeStep.fromJS(data["Step"]) : <any>undefined;
-        }
-    }
-
-    static fromJS(data: any): DateTimeBinRange {
-        data = typeof data === 'object' ? data : {};
-        let result = new DateTimeBinRange();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Step"] = this.step ? this.step.toJSON() : <any>undefined;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IDateTimeBinRange extends IBinRange {
-    step?: DateTimeStep | undefined;
-}
-
-export class DateTimeStep implements IDateTimeStep {
-    dateTimeStepGranularity?: DateTimeStepGranularity | undefined;
-    dateTimeStepValue?: number | undefined;
-    dateTimeStepMaxValue?: number | undefined;
-
-    constructor(data?: IDateTimeStep) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.dateTimeStepGranularity = data["DateTimeStepGranularity"];
-            this.dateTimeStepValue = data["DateTimeStepValue"];
-            this.dateTimeStepMaxValue = data["DateTimeStepMaxValue"];
-        }
-    }
-
-    static fromJS(data: any): DateTimeStep {
-        data = typeof data === 'object' ? data : {};
-        let result = new DateTimeStep();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["DateTimeStepGranularity"] = this.dateTimeStepGranularity;
-        data["DateTimeStepValue"] = this.dateTimeStepValue;
-        data["DateTimeStepMaxValue"] = this.dateTimeStepMaxValue;
-        return data;
-    }
-}
-
-export interface IDateTimeStep {
-    dateTimeStepGranularity?: DateTimeStepGranularity | undefined;
-    dateTimeStepValue?: number | undefined;
-    dateTimeStepMaxValue?: number | undefined;
-}
-
-export enum DateTimeStepGranularity {
-    Second = 0,
-    Minute = 1,
-    Hour = 2,
-    Day = 3,
-    Month = 4,
-    Year = 5,
-}
-
-export class Bin implements IBin {
-    aggregateResults?: AggregateResult[] | undefined;
-    count?: number | undefined;
-    binIndex?: BinIndex | undefined;
-    spans?: Span[] | undefined;
-    xSize?: number | undefined;
-    ySize?: number | undefined;
-
-    constructor(data?: IBin) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            if (data["AggregateResults"] && data["AggregateResults"].constructor === Array) {
-                this.aggregateResults = [];
-                for (let item of data["AggregateResults"]) {
-                    let fromJs = AggregateResult.fromJS(item);
-                    if (fromJs)
-                        this.aggregateResults.push(fromJs);
-                }
-            }
-            this.count = data["Count"];
-            this.binIndex = data["BinIndex"] ? BinIndex.fromJS(data["BinIndex"]) : <any>undefined;
-            if (data["Spans"] && data["Spans"].constructor === Array) {
-                this.spans = [];
-                for (let item of data["Spans"])
-                    this.spans.push(Span.fromJS(item));
-            }
-            this.xSize = data["XSize"];
-            this.ySize = data["YSize"];
-        }
-    }
-
-    static fromJS(data: any): Bin {
-        data = typeof data === 'object' ? data : {};
-        let result = new Bin();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.aggregateResults && this.aggregateResults.constructor === Array) {
-            data["AggregateResults"] = [];
-            for (let item of this.aggregateResults)
-                data["AggregateResults"].push(item.toJSON());
-        }
-        data["Count"] = this.count;
-        data["BinIndex"] = this.binIndex ? this.binIndex.toJSON() : <any>undefined;
-        if (this.spans && this.spans.constructor === Array) {
-            data["Spans"] = [];
-            for (let item of this.spans)
-                data["Spans"].push(item.toJSON());
-        }
-        data["XSize"] = this.xSize;
-        data["YSize"] = this.ySize;
-        return data;
-    }
-}
-
-export interface IBin {
-    aggregateResults?: AggregateResult[] | undefined;
-    count?: number | undefined;
-    binIndex?: BinIndex | undefined;
-    spans?: Span[] | undefined;
-    xSize?: number | undefined;
-    ySize?: number | undefined;
-}
-
-export class BinIndex implements IBinIndex {
-    indices?: number[] | undefined;
-    flatIndex?: number | undefined;
-
-    constructor(data?: IBinIndex) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            if (data["Indices"] && data["Indices"].constructor === Array) {
-                this.indices = [];
-                for (let item of data["Indices"])
-                    this.indices.push(item);
-            }
-            this.flatIndex = data["FlatIndex"];
-        }
-    }
-
-    static fromJS(data: any): BinIndex {
-        data = typeof data === 'object' ? data : {};
-        let result = new BinIndex();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.indices && this.indices.constructor === Array) {
-            data["Indices"] = [];
-            for (let item of this.indices)
-                data["Indices"].push(item);
-        }
-        data["FlatIndex"] = this.flatIndex;
-        return data;
-    }
-}
-
-export interface IBinIndex {
-    indices?: number[] | undefined;
-    flatIndex?: number | undefined;
-}
-
-export class Span implements ISpan {
-    min?: number | undefined;
-    max?: number | undefined;
-    index?: number | undefined;
-
-    constructor(data?: ISpan) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.min = data["Min"];
-            this.max = data["Max"];
-            this.index = data["Index"];
-        }
-    }
-
-    static fromJS(data: any): Span {
-        data = typeof data === 'object' ? data : {};
-        let result = new Span();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Min"] = this.min;
-        data["Max"] = this.max;
-        data["Index"] = this.index;
-        return data;
-    }
-}
-
-export interface ISpan {
-    min?: number | undefined;
-    max?: number | undefined;
-    index?: number | undefined;
-}
-
-export class ModelWealthResult extends Result implements IModelWealthResult {
-    wealth?: number | undefined;
-    startWealth?: number | undefined;
-
-    constructor(data?: IModelWealthResult) {
-        super(data);
-        this._discriminator = "ModelWealthResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.wealth = data["Wealth"];
-            this.startWealth = data["StartWealth"];
-        }
-    }
-
-    static fromJS(data: any): ModelWealthResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new ModelWealthResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Wealth"] = this.wealth;
-        data["StartWealth"] = this.startWealth;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IModelWealthResult extends IResult {
-    wealth?: number | undefined;
-    startWealth?: number | undefined;
-}
-
-export abstract class HypothesisTestResult extends Result implements IHypothesisTestResult {
-    pValue?: number | undefined;
-    statistic?: number | undefined;
-    support?: number | undefined;
-    sampleSizes?: number[] | undefined;
-    errorMessage?: string | undefined;
-
-    constructor(data?: IHypothesisTestResult) {
-        super(data);
-        this._discriminator = "HypothesisTestResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.pValue = data["PValue"];
-            this.statistic = data["Statistic"];
-            this.support = data["Support"];
-            if (data["SampleSizes"] && data["SampleSizes"].constructor === Array) {
-                this.sampleSizes = [];
-                for (let item of data["SampleSizes"])
-                    this.sampleSizes.push(item);
-            }
-            this.errorMessage = data["ErrorMessage"];
-        }
-    }
-
-    static fromJS(data: any): HypothesisTestResult {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "ChiSquaredTestResult") {
-            let result = new ChiSquaredTestResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "CorrelationTestResult") {
-            let result = new CorrelationTestResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "KSTestResult") {
-            let result = new KSTestResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "RootMeanSquareTestResult") {
-            let result = new RootMeanSquareTestResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "TTestResult") {
-            let result = new TTestResult();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'HypothesisTestResult' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["PValue"] = this.pValue;
-        data["Statistic"] = this.statistic;
-        data["Support"] = this.support;
-        if (this.sampleSizes && this.sampleSizes.constructor === Array) {
-            data["SampleSizes"] = [];
-            for (let item of this.sampleSizes)
-                data["SampleSizes"].push(item);
-        }
-        data["ErrorMessage"] = this.errorMessage;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IHypothesisTestResult extends IResult {
-    pValue?: number | undefined;
-    statistic?: number | undefined;
-    support?: number | undefined;
-    sampleSizes?: number[] | undefined;
-    errorMessage?: string | undefined;
-}
-
-export abstract class ModelOperationResult extends Result implements IModelOperationResult {
-    modelId?: ModelId | undefined;
-
-    constructor(data?: IModelOperationResult) {
-        super(data);
-        this._discriminator = "ModelOperationResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.modelId = data["ModelId"] ? ModelId.fromJS(data["ModelId"]) : <any>undefined;
-        }
-    }
-
-    static fromJS(data: any): ModelOperationResult {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "NewModelOperationResult") {
-            let result = new NewModelOperationResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "AddComparisonResult") {
-            let result = new AddComparisonResult();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "GetModelStateResult") {
-            let result = new GetModelStateResult();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'ModelOperationResult' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["ModelId"] = this.modelId ? this.modelId.toJSON() : <any>undefined;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IModelOperationResult extends IResult {
-    modelId?: ModelId | undefined;
-}
-
-export class RecommenderResult extends Result implements IRecommenderResult {
-    recommendedHistograms?: RecommendedHistogram[] | undefined;
-    totalCount?: number | undefined;
-
-    constructor(data?: IRecommenderResult) {
-        super(data);
-        this._discriminator = "RecommenderResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["RecommendedHistograms"] && data["RecommendedHistograms"].constructor === Array) {
-                this.recommendedHistograms = [];
-                for (let item of data["RecommendedHistograms"])
-                    this.recommendedHistograms.push(RecommendedHistogram.fromJS(item));
-            }
-            this.totalCount = data["TotalCount"];
-        }
-    }
-
-    static fromJS(data: any): RecommenderResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new RecommenderResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.recommendedHistograms && this.recommendedHistograms.constructor === Array) {
-            data["RecommendedHistograms"] = [];
-            for (let item of this.recommendedHistograms)
-                data["RecommendedHistograms"].push(item.toJSON());
-        }
-        data["TotalCount"] = this.totalCount;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IRecommenderResult extends IResult {
-    recommendedHistograms?: RecommendedHistogram[] | undefined;
-    totalCount?: number | undefined;
-}
-
-export class RecommendedHistogram implements IRecommendedHistogram {
-    histogramResult?: HistogramResult | undefined;
-    selectedBinIndices?: BinIndex[] | undefined;
-    selections?: Selection[] | undefined;
-    pValue?: number | undefined;
-    significance?: boolean | undefined;
-    decision?: Decision | undefined;
-    effectSize?: number | undefined;
-    hypothesisTestResult?: HypothesisTestResult | undefined;
-    id?: string | undefined;
-    xAttribute?: Attribute | undefined;
-    yAttribute?: Attribute | undefined;
-
-    constructor(data?: IRecommendedHistogram) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.histogramResult = data["HistogramResult"] ? HistogramResult.fromJS(data["HistogramResult"]) : <any>undefined;
-            if (data["SelectedBinIndices"] && data["SelectedBinIndices"].constructor === Array) {
-                this.selectedBinIndices = [];
-                for (let item of data["SelectedBinIndices"])
-                    this.selectedBinIndices.push(BinIndex.fromJS(item));
-            }
-            if (data["Selections"] && data["Selections"].constructor === Array) {
-                this.selections = [];
-                for (let item of data["Selections"])
-                    this.selections.push(Selection.fromJS(item));
-            }
-            this.pValue = data["PValue"];
-            this.significance = data["Significance"];
-            this.decision = data["Decision"] ? Decision.fromJS(data["Decision"]) : <any>undefined;
-            this.effectSize = data["EffectSize"];
-            this.hypothesisTestResult = data["HypothesisTestResult"] ? HypothesisTestResult.fromJS(data["HypothesisTestResult"]) : <any>undefined;
-            this.id = data["Id"];
-            this.xAttribute = data["XAttribute"] ? Attribute.fromJS(data["XAttribute"]) : <any>undefined;
-            this.yAttribute = data["YAttribute"] ? Attribute.fromJS(data["YAttribute"]) : <any>undefined;
-        }
-    }
-
-    static fromJS(data: any): RecommendedHistogram {
-        data = typeof data === 'object' ? data : {};
-        let result = new RecommendedHistogram();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["HistogramResult"] = this.histogramResult ? this.histogramResult.toJSON() : <any>undefined;
-        if (this.selectedBinIndices && this.selectedBinIndices.constructor === Array) {
-            data["SelectedBinIndices"] = [];
-            for (let item of this.selectedBinIndices)
-                data["SelectedBinIndices"].push(item.toJSON());
-        }
-        if (this.selections && this.selections.constructor === Array) {
-            data["Selections"] = [];
-            for (let item of this.selections)
-                data["Selections"].push(item.toJSON());
-        }
-        data["PValue"] = this.pValue;
-        data["Significance"] = this.significance;
-        data["Decision"] = this.decision ? this.decision.toJSON() : <any>undefined;
-        data["EffectSize"] = this.effectSize;
-        data["HypothesisTestResult"] = this.hypothesisTestResult ? this.hypothesisTestResult.toJSON() : <any>undefined;
-        data["Id"] = this.id;
-        data["XAttribute"] = this.xAttribute ? this.xAttribute.toJSON() : <any>undefined;
-        data["YAttribute"] = this.yAttribute ? this.yAttribute.toJSON() : <any>undefined;
-        return data;
-    }
-}
-
-export interface IRecommendedHistogram {
-    histogramResult?: HistogramResult | undefined;
-    selectedBinIndices?: BinIndex[] | undefined;
-    selections?: Selection[] | undefined;
-    pValue?: number | undefined;
-    significance?: boolean | undefined;
-    decision?: Decision | undefined;
-    effectSize?: number | undefined;
-    hypothesisTestResult?: HypothesisTestResult | undefined;
-    id?: string | undefined;
-    xAttribute?: Attribute | undefined;
-    yAttribute?: Attribute | undefined;
-}
-
-export class Selection implements ISelection {
-    statements?: Statement[] | undefined;
-    filterHistogramOperationReference?: IOperationReference | undefined;
-
-    constructor(data?: ISelection) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            if (data["Statements"] && data["Statements"].constructor === Array) {
-                this.statements = [];
-                for (let item of data["Statements"])
-                    this.statements.push(Statement.fromJS(item));
-            }
-            this.filterHistogramOperationReference = data["FilterHistogramOperationReference"] ? IOperationReference.fromJS(data["FilterHistogramOperationReference"]) : <any>undefined;
-        }
-    }
-
-    static fromJS(data: any): Selection {
-        data = typeof data === 'object' ? data : {};
-        let result = new Selection();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.statements && this.statements.constructor === Array) {
-            data["Statements"] = [];
-            for (let item of this.statements)
-                data["Statements"].push(item.toJSON());
-        }
-        data["FilterHistogramOperationReference"] = this.filterHistogramOperationReference ? this.filterHistogramOperationReference.toJSON() : <any>undefined;
-        return data;
-    }
-}
-
-export interface ISelection {
-    statements?: Statement[] | undefined;
-    filterHistogramOperationReference?: IOperationReference | undefined;
-}
-
-export class Statement implements IStatement {
-    attribute?: Attribute | undefined;
-    predicate?: Predicate | undefined;
-    value?: any | undefined;
-
-    constructor(data?: IStatement) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.attribute = data["Attribute"] ? Attribute.fromJS(data["Attribute"]) : <any>undefined;
-            this.predicate = data["Predicate"];
-            this.value = data["Value"];
-        }
-    }
-
-    static fromJS(data: any): Statement {
-        data = typeof data === 'object' ? data : {};
-        let result = new Statement();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Attribute"] = this.attribute ? this.attribute.toJSON() : <any>undefined;
-        data["Predicate"] = this.predicate;
-        data["Value"] = this.value;
-        return data;
-    }
-}
-
-export interface IStatement {
-    attribute?: Attribute | undefined;
-    predicate?: Predicate | undefined;
-    value?: any | undefined;
-}
-
-export enum Predicate {
-    EQUALS = 0,
-    LIKE = 1,
-    GREATER_THAN = 2,
-    LESS_THAN = 3,
-    GREATER_THAN_EQUAL = 4,
-    LESS_THAN_EQUAL = 5,
-    STARTS_WITH = 6,
-    ENDS_WITH = 7,
-    CONTAINS = 8,
-}
-
-export abstract class IOperationReference implements IIOperationReference {
-    id?: string | undefined;
-
-    protected _discriminator: string;
-
-    constructor(data?: IIOperationReference) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-        this._discriminator = "IOperationReference";
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.id = data["Id"];
-        }
-    }
-
-    static fromJS(data: any): IOperationReference {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "OperationReference") {
-            let result = new OperationReference();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'IOperationReference' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["discriminator"] = this._discriminator;
-        data["Id"] = this.id;
-        return data;
-    }
-}
-
-export interface IIOperationReference {
-    id?: string | undefined;
-}
-
-export class OperationReference extends IOperationReference implements IOperationReference {
-    id?: string | undefined;
-
-    constructor(data?: IOperationReference) {
-        super(data);
-        this._discriminator = "OperationReference";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.id = data["Id"];
-        }
-    }
-
-    static fromJS(data: any): OperationReference {
-        data = typeof data === 'object' ? data : {};
-        let result = new OperationReference();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Id"] = this.id;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IOperationReference extends IIOperationReference {
-    id?: string | undefined;
-}
-
-export class Decision extends Result implements IDecision {
-    comparisonId?: ComparisonId | undefined;
-    riskControlType?: RiskControlType | undefined;
-    significance?: boolean | undefined;
-    pValue?: number | undefined;
-    lhs?: number | undefined;
-    significanceLevel?: number | undefined;
-    sampleSizeEstimate?: number | undefined;
-
-    constructor(data?: IDecision) {
-        super(data);
-        this._discriminator = "Decision";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.comparisonId = data["ComparisonId"] ? ComparisonId.fromJS(data["ComparisonId"]) : <any>undefined;
-            this.riskControlType = data["RiskControlType"];
-            this.significance = data["Significance"];
-            this.pValue = data["PValue"];
-            this.lhs = data["Lhs"];
-            this.significanceLevel = data["SignificanceLevel"];
-            this.sampleSizeEstimate = data["SampleSizeEstimate"];
-        }
-    }
-
-    static fromJS(data: any): Decision {
-        data = typeof data === 'object' ? data : {};
-        let result = new Decision();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["ComparisonId"] = this.comparisonId ? this.comparisonId.toJSON() : <any>undefined;
-        data["RiskControlType"] = this.riskControlType;
-        data["Significance"] = this.significance;
-        data["PValue"] = this.pValue;
-        data["Lhs"] = this.lhs;
-        data["SignificanceLevel"] = this.significanceLevel;
-        data["SampleSizeEstimate"] = this.sampleSizeEstimate;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IDecision extends IResult {
-    comparisonId?: ComparisonId | undefined;
-    riskControlType?: RiskControlType | undefined;
-    significance?: boolean | undefined;
-    pValue?: number | undefined;
-    lhs?: number | undefined;
-    significanceLevel?: number | undefined;
-    sampleSizeEstimate?: number | undefined;
-}
-
-export class ComparisonId implements IComparisonId {
-    value?: string | undefined;
-
-    constructor(data?: IComparisonId) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.value = data["Value"];
-        }
-    }
-
-    static fromJS(data: any): ComparisonId {
-        data = typeof data === 'object' ? data : {};
-        let result = new ComparisonId();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Value"] = this.value;
-        return data;
-    }
-}
-
-export interface IComparisonId {
-    value?: string | undefined;
-}
-
-export class OptimizerResult extends Result implements IOptimizerResult {
-    topKSolutions?: Solution[] | undefined;
-
-    constructor(data?: IOptimizerResult) {
-        super(data);
-        this._discriminator = "OptimizerResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["TopKSolutions"] && data["TopKSolutions"].constructor === Array) {
-                this.topKSolutions = [];
-                for (let item of data["TopKSolutions"])
-                    this.topKSolutions.push(Solution.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): OptimizerResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new OptimizerResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.topKSolutions && this.topKSolutions.constructor === Array) {
-            data["TopKSolutions"] = [];
-            for (let item of this.topKSolutions)
-                data["TopKSolutions"].push(item.toJSON());
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IOptimizerResult extends IResult {
-    topKSolutions?: Solution[] | undefined;
-}
-
-export class Solution implements ISolution {
-    solutionId?: string | undefined;
-    stepDescriptions?: StepDescription[] | undefined;
-    pipelineDescription?: PipelineDescription | undefined;
-    score?: Score | undefined;
-    naiveScore?: Score | undefined;
-
-    constructor(data?: ISolution) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.solutionId = data["SolutionId"];
-            if (data["StepDescriptions"] && data["StepDescriptions"].constructor === Array) {
-                this.stepDescriptions = [];
-                for (let item of data["StepDescriptions"])
-                    this.stepDescriptions.push(StepDescription.fromJS(item));
-            }
-            this.pipelineDescription = data["PipelineDescription"] ? PipelineDescription.fromJS(data["PipelineDescription"]) : <any>undefined;
-            this.score = data["Score"] ? Score.fromJS(data["Score"]) : <any>undefined;
-            this.naiveScore = data["NaiveScore"] ? Score.fromJS(data["NaiveScore"]) : <any>undefined;
-        }
-    }
-
-    static fromJS(data: any): Solution {
-        data = typeof data === 'object' ? data : {};
-        let result = new Solution();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["SolutionId"] = this.solutionId;
-        if (this.stepDescriptions && this.stepDescriptions.constructor === Array) {
-            data["StepDescriptions"] = [];
-            for (let item of this.stepDescriptions)
-                data["StepDescriptions"].push(item.toJSON());
-        }
-        data["PipelineDescription"] = this.pipelineDescription ? this.pipelineDescription.toJSON() : <any>undefined;
-        data["Score"] = this.score ? this.score.toJSON() : <any>undefined;
-        data["NaiveScore"] = this.naiveScore ? this.naiveScore.toJSON() : <any>undefined;
-        return data;
-    }
-}
-
-export interface ISolution {
-    solutionId?: string | undefined;
-    stepDescriptions?: StepDescription[] | undefined;
-    pipelineDescription?: PipelineDescription | undefined;
-    score?: Score | undefined;
-    naiveScore?: Score | undefined;
-}
-
-export class StepDescription implements IStepDescription {
-
-    protected _discriminator: string;
-
-    constructor(data?: IStepDescription) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-        this._discriminator = "StepDescription";
-    }
-
-    init(data?: any) {
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): StepDescription {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "SubpipelineStepDescription") {
-            let result = new SubpipelineStepDescription();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "PrimitiveStepDescription") {
-            let result = new PrimitiveStepDescription();
-            result.init(data);
-            return result;
-        }
-        let result = new StepDescription();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["discriminator"] = this._discriminator;
-        return data;
-    }
-}
-
-export interface IStepDescription {
-}
-
-export class SubpipelineStepDescription extends StepDescription implements ISubpipelineStepDescription {
-    steps?: StepDescription[] | undefined;
-
-    constructor(data?: ISubpipelineStepDescription) {
-        super(data);
-        this._discriminator = "SubpipelineStepDescription";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["Steps"] && data["Steps"].constructor === Array) {
-                this.steps = [];
-                for (let item of data["Steps"])
-                    this.steps.push(StepDescription.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): SubpipelineStepDescription {
-        data = typeof data === 'object' ? data : {};
-        let result = new SubpipelineStepDescription();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.steps && this.steps.constructor === Array) {
-            data["Steps"] = [];
-            for (let item of this.steps)
-                data["Steps"].push(item.toJSON());
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ISubpipelineStepDescription extends IStepDescription {
-    steps?: StepDescription[] | undefined;
-}
-
-export class PipelineDescription implements IPipelineDescription {
-    id?: string | undefined;
-    name?: string | undefined;
-    description?: string | undefined;
-    inputs?: PipelineDescriptionInput[] | undefined;
-    outputs?: PipelineDescriptionOutput[] | undefined;
-    steps?: PipelineDescriptionStep[] | undefined;
-
-    constructor(data?: IPipelineDescription) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.id = data["Id"];
-            this.name = data["Name"];
-            this.description = data["Description"];
-            if (data["Inputs"] && data["Inputs"].constructor === Array) {
-                this.inputs = [];
-                for (let item of data["Inputs"])
-                    this.inputs.push(PipelineDescriptionInput.fromJS(item));
-            }
-            if (data["Outputs"] && data["Outputs"].constructor === Array) {
-                this.outputs = [];
-                for (let item of data["Outputs"])
-                    this.outputs.push(PipelineDescriptionOutput.fromJS(item));
-            }
-            if (data["Steps"] && data["Steps"].constructor === Array) {
-                this.steps = [];
-                for (let item of data["Steps"])
-                    this.steps.push(PipelineDescriptionStep.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): PipelineDescription {
-        data = typeof data === 'object' ? data : {};
-        let result = new PipelineDescription();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Id"] = this.id;
-        data["Name"] = this.name;
-        data["Description"] = this.description;
-        if (this.inputs && this.inputs.constructor === Array) {
-            data["Inputs"] = [];
-            for (let item of this.inputs)
-                data["Inputs"].push(item.toJSON());
-        }
-        if (this.outputs && this.outputs.constructor === Array) {
-            data["Outputs"] = [];
-            for (let item of this.outputs)
-                data["Outputs"].push(item.toJSON());
-        }
-        if (this.steps && this.steps.constructor === Array) {
-            data["Steps"] = [];
-            for (let item of this.steps)
-                data["Steps"].push(item.toJSON());
-        }
-        return data;
-    }
-}
-
-export interface IPipelineDescription {
-    id?: string | undefined;
-    name?: string | undefined;
-    description?: string | undefined;
-    inputs?: PipelineDescriptionInput[] | undefined;
-    outputs?: PipelineDescriptionOutput[] | undefined;
-    steps?: PipelineDescriptionStep[] | undefined;
-}
-
-export class PipelineDescriptionInput implements IPipelineDescriptionInput {
-    name?: string | undefined;
-
-    constructor(data?: IPipelineDescriptionInput) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.name = data["Name"];
-        }
-    }
-
-    static fromJS(data: any): PipelineDescriptionInput {
-        data = typeof data === 'object' ? data : {};
-        let result = new PipelineDescriptionInput();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Name"] = this.name;
-        return data;
-    }
-}
-
-export interface IPipelineDescriptionInput {
-    name?: string | undefined;
-}
-
-export class PipelineDescriptionOutput implements IPipelineDescriptionOutput {
-    name?: string | undefined;
-    data?: string | undefined;
-
-    constructor(data?: IPipelineDescriptionOutput) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.name = data["Name"];
-            this.data = data["Data"];
-        }
-    }
-
-    static fromJS(data: any): PipelineDescriptionOutput {
-        data = typeof data === 'object' ? data : {};
-        let result = new PipelineDescriptionOutput();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Name"] = this.name;
-        data["Data"] = this.data;
-        return data;
-    }
-}
-
-export interface IPipelineDescriptionOutput {
-    name?: string | undefined;
-    data?: string | undefined;
-}
-
-export class PipelineDescriptionStep implements IPipelineDescriptionStep {
-    outputs?: StepOutput[] | undefined;
-
-    protected _discriminator: string;
-
-    constructor(data?: IPipelineDescriptionStep) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-        this._discriminator = "PipelineDescriptionStep";
-    }
-
-    init(data?: any) {
-        if (data) {
-            if (data["Outputs"] && data["Outputs"].constructor === Array) {
-                this.outputs = [];
-                for (let item of data["Outputs"])
-                    this.outputs.push(StepOutput.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): PipelineDescriptionStep {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "PlaceholderPipelineDescriptionStep") {
-            let result = new PlaceholderPipelineDescriptionStep();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "SubpipelinePipelineDescriptionStep") {
-            let result = new SubpipelinePipelineDescriptionStep();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "PrimitivePipelineDescriptionStep") {
-            let result = new PrimitivePipelineDescriptionStep();
-            result.init(data);
-            return result;
-        }
-        let result = new PipelineDescriptionStep();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["discriminator"] = this._discriminator;
-        if (this.outputs && this.outputs.constructor === Array) {
-            data["Outputs"] = [];
-            for (let item of this.outputs)
-                data["Outputs"].push(item.toJSON());
-        }
-        return data;
-    }
-}
-
-export interface IPipelineDescriptionStep {
-    outputs?: StepOutput[] | undefined;
-}
-
-export class StepOutput implements IStepOutput {
-    id?: string | undefined;
-
-    constructor(data?: IStepOutput) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.id = data["Id"];
-        }
-    }
-
-    static fromJS(data: any): StepOutput {
-        data = typeof data === 'object' ? data : {};
-        let result = new StepOutput();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Id"] = this.id;
-        return data;
-    }
-}
-
-export interface IStepOutput {
-    id?: string | undefined;
-}
-
-export class PlaceholderPipelineDescriptionStep extends PipelineDescriptionStep implements IPlaceholderPipelineDescriptionStep {
-    inputs?: StepInput[] | undefined;
-
-    constructor(data?: IPlaceholderPipelineDescriptionStep) {
-        super(data);
-        this._discriminator = "PlaceholderPipelineDescriptionStep";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["Inputs"] && data["Inputs"].constructor === Array) {
-                this.inputs = [];
-                for (let item of data["Inputs"])
-                    this.inputs.push(StepInput.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): PlaceholderPipelineDescriptionStep {
-        data = typeof data === 'object' ? data : {};
-        let result = new PlaceholderPipelineDescriptionStep();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.inputs && this.inputs.constructor === Array) {
-            data["Inputs"] = [];
-            for (let item of this.inputs)
-                data["Inputs"].push(item.toJSON());
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IPlaceholderPipelineDescriptionStep extends IPipelineDescriptionStep {
-    inputs?: StepInput[] | undefined;
-}
-
-export class StepInput implements IStepInput {
-    data?: string | undefined;
-
-    constructor(data?: IStepInput) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.data = data["Data"];
-        }
-    }
-
-    static fromJS(data: any): StepInput {
-        data = typeof data === 'object' ? data : {};
-        let result = new StepInput();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Data"] = this.data;
-        return data;
-    }
-}
-
-export interface IStepInput {
-    data?: string | undefined;
-}
-
-export class SubpipelinePipelineDescriptionStep extends PipelineDescriptionStep implements ISubpipelinePipelineDescriptionStep {
-    pipelineDescription?: PipelineDescription | undefined;
-    inputs?: StepInput[] | undefined;
-
-    constructor(data?: ISubpipelinePipelineDescriptionStep) {
-        super(data);
-        this._discriminator = "SubpipelinePipelineDescriptionStep";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.pipelineDescription = data["PipelineDescription"] ? PipelineDescription.fromJS(data["PipelineDescription"]) : <any>undefined;
-            if (data["Inputs"] && data["Inputs"].constructor === Array) {
-                this.inputs = [];
-                for (let item of data["Inputs"])
-                    this.inputs.push(StepInput.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): SubpipelinePipelineDescriptionStep {
-        data = typeof data === 'object' ? data : {};
-        let result = new SubpipelinePipelineDescriptionStep();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["PipelineDescription"] = this.pipelineDescription ? this.pipelineDescription.toJSON() : <any>undefined;
-        if (this.inputs && this.inputs.constructor === Array) {
-            data["Inputs"] = [];
-            for (let item of this.inputs)
-                data["Inputs"].push(item.toJSON());
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ISubpipelinePipelineDescriptionStep extends IPipelineDescriptionStep {
-    pipelineDescription?: PipelineDescription | undefined;
-    inputs?: StepInput[] | undefined;
-}
-
-export class PrimitivePipelineDescriptionStep extends PipelineDescriptionStep implements IPrimitivePipelineDescriptionStep {
-    primitive?: Primitive | undefined;
-    arguments?: { [key: string]: PrimitiveStepArgument; } | undefined;
-    hyperparams?: { [key: string]: PrimitiveStepHyperparameter; } | undefined;
-
-    constructor(data?: IPrimitivePipelineDescriptionStep) {
-        super(data);
-        this._discriminator = "PrimitivePipelineDescriptionStep";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.primitive = data["Primitive"] ? Primitive.fromJS(data["Primitive"]) : <any>undefined;
-            if (data["Arguments"]) {
-                this.arguments = {};
-                for (let key in data["Arguments"]) {
-                    if (data["Arguments"].hasOwnProperty(key))
-                        this.arguments[key] = data["Arguments"][key] ? PrimitiveStepArgument.fromJS(data["Arguments"][key]) : new PrimitiveStepArgument();
-                }
-            }
-            if (data["Hyperparams"]) {
-                this.hyperparams = {};
-                for (let key in data["Hyperparams"]) {
-                    if (data["Hyperparams"].hasOwnProperty(key))
-                        this.hyperparams[key] = data["Hyperparams"][key] ? PrimitiveStepHyperparameter.fromJS(data["Hyperparams"][key]) : new PrimitiveStepHyperparameter();
-                }
-            }
-        }
-    }
-
-    static fromJS(data: any): PrimitivePipelineDescriptionStep {
-        data = typeof data === 'object' ? data : {};
-        let result = new PrimitivePipelineDescriptionStep();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Primitive"] = this.primitive ? this.primitive.toJSON() : <any>undefined;
-        if (this.arguments) {
-            data["Arguments"] = {};
-            for (let key in this.arguments) {
-                if (this.arguments.hasOwnProperty(key))
-                    data["Arguments"][key] = this.arguments[key];
-            }
-        }
-        if (this.hyperparams) {
-            data["Hyperparams"] = {};
-            for (let key in this.hyperparams) {
-                if (this.hyperparams.hasOwnProperty(key))
-                    data["Hyperparams"][key] = this.hyperparams[key];
-            }
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IPrimitivePipelineDescriptionStep extends IPipelineDescriptionStep {
-    primitive?: Primitive | undefined;
-    arguments?: { [key: string]: PrimitiveStepArgument; } | undefined;
-    hyperparams?: { [key: string]: PrimitiveStepHyperparameter; } | undefined;
-}
-
-export class Primitive implements IPrimitive {
-    id?: string | undefined;
-    version?: string | undefined;
-    pythonPath?: string | undefined;
-    name?: string | undefined;
-    digest?: string | undefined;
-
-    constructor(data?: IPrimitive) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.id = data["Id"];
-            this.version = data["Version"];
-            this.pythonPath = data["PythonPath"];
-            this.name = data["Name"];
-            this.digest = data["Digest"];
-        }
-    }
-
-    static fromJS(data: any): Primitive {
-        data = typeof data === 'object' ? data : {};
-        let result = new Primitive();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Id"] = this.id;
-        data["Version"] = this.version;
-        data["PythonPath"] = this.pythonPath;
-        data["Name"] = this.name;
-        data["Digest"] = this.digest;
-        return data;
-    }
-}
-
-export interface IPrimitive {
-    id?: string | undefined;
-    version?: string | undefined;
-    pythonPath?: string | undefined;
-    name?: string | undefined;
-    digest?: string | undefined;
-}
-
-export class PrimitiveStepHyperparameter implements IPrimitiveStepHyperparameter {
-
-    protected _discriminator: string;
-
-    constructor(data?: IPrimitiveStepHyperparameter) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-        this._discriminator = "PrimitiveStepHyperparameter";
-    }
-
-    init(data?: any) {
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): PrimitiveStepHyperparameter {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "PrimitiveStepArgument") {
-            let result = new PrimitiveStepArgument();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "DataArguments") {
-            let result = new DataArguments();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "PrimitiveArgument") {
-            let result = new PrimitiveArgument();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "PrimitiveArguments") {
-            let result = new PrimitiveArguments();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "ValueArgument") {
-            let result = new ValueArgument();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "ContainerArgument") {
-            let result = new ContainerArgument();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "DataArgument") {
-            let result = new DataArgument();
-            result.init(data);
-            return result;
-        }
-        let result = new PrimitiveStepHyperparameter();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["discriminator"] = this._discriminator;
-        return data;
-    }
-}
-
-export interface IPrimitiveStepHyperparameter {
-}
-
-export class PrimitiveStepArgument extends PrimitiveStepHyperparameter implements IPrimitiveStepArgument {
-
-    protected _discriminator: string;
-
-    constructor(data?: IPrimitiveStepArgument) {
-        super(data);
-        this._discriminator = "PrimitiveStepArgument";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): PrimitiveStepArgument {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "ContainerArgument") {
-            let result = new ContainerArgument();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "DataArgument") {
-            let result = new DataArgument();
-            result.init(data);
-            return result;
-        }
-        let result = new PrimitiveStepArgument();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["discriminator"] = this._discriminator;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IPrimitiveStepArgument extends IPrimitiveStepHyperparameter {
-}
-
-export class DataArguments extends PrimitiveStepHyperparameter implements IDataArguments {
-    data?: string[] | undefined;
-
-    constructor(data?: IDataArguments) {
-        super(data);
-        this._discriminator = "DataArguments";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["Data"] && data["Data"].constructor === Array) {
-                this.data = [];
-                for (let item of data["Data"])
-                    this.data.push(item);
-            }
-        }
-    }
-
-    static fromJS(data: any): DataArguments {
-        data = typeof data === 'object' ? data : {};
-        let result = new DataArguments();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.data && this.data.constructor === Array) {
-            data["Data"] = [];
-            for (let item of this.data)
-                data["Data"].push(item);
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IDataArguments extends IPrimitiveStepHyperparameter {
-    data?: string[] | undefined;
-}
-
-export class PrimitiveArgument extends PrimitiveStepHyperparameter implements IPrimitiveArgument {
-    data?: number | undefined;
-
-    constructor(data?: IPrimitiveArgument) {
-        super(data);
-        this._discriminator = "PrimitiveArgument";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.data = data["Data"];
-        }
-    }
-
-    static fromJS(data: any): PrimitiveArgument {
-        data = typeof data === 'object' ? data : {};
-        let result = new PrimitiveArgument();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Data"] = this.data;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IPrimitiveArgument extends IPrimitiveStepHyperparameter {
-    data?: number | undefined;
-}
-
-export class PrimitiveArguments extends PrimitiveStepHyperparameter implements IPrimitiveArguments {
-    data?: number[] | undefined;
-
-    constructor(data?: IPrimitiveArguments) {
-        super(data);
-        this._discriminator = "PrimitiveArguments";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["Data"] && data["Data"].constructor === Array) {
-                this.data = [];
-                for (let item of data["Data"])
-                    this.data.push(item);
-            }
-        }
-    }
-
-    static fromJS(data: any): PrimitiveArguments {
-        data = typeof data === 'object' ? data : {};
-        let result = new PrimitiveArguments();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.data && this.data.constructor === Array) {
-            data["Data"] = [];
-            for (let item of this.data)
-                data["Data"].push(item);
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IPrimitiveArguments extends IPrimitiveStepHyperparameter {
-    data?: number[] | undefined;
-}
-
-export class ValueArgument extends PrimitiveStepHyperparameter implements IValueArgument {
-    data?: Value | undefined;
-
-    constructor(data?: IValueArgument) {
-        super(data);
-        this._discriminator = "ValueArgument";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.data = data["Data"] ? Value.fromJS(data["Data"]) : <any>undefined;
-        }
-    }
-
-    static fromJS(data: any): ValueArgument {
-        data = typeof data === 'object' ? data : {};
-        let result = new ValueArgument();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Data"] = this.data ? this.data.toJSON() : <any>undefined;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IValueArgument extends IPrimitiveStepHyperparameter {
-    data?: Value | undefined;
-}
-
-export abstract class Value implements IValue {
-
-    protected _discriminator: string;
-
-    constructor(data?: IValue) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-        this._discriminator = "Value";
-    }
-
-    init(data?: any) {
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): Value {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "ErrorValue") {
-            let result = new ErrorValue();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "DoubleValue") {
-            let result = new DoubleValue();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "LongValue") {
-            let result = new LongValue();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "BoolValue") {
-            let result = new BoolValue();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "StringValue") {
-            let result = new StringValue();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "DatasetUriValue") {
-            let result = new DatasetUriValue();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "CsvUriValue") {
-            let result = new CsvUriValue();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "PickleUriValue") {
-            let result = new PickleUriValue();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "PickleBlobValue") {
-            let result = new PickleBlobValue();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "PlasmaIdValue") {
-            let result = new PlasmaIdValue();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "BytesValue") {
-            let result = new BytesValue();
-            result.init(data);
-            return result;
-        }
-        if (data["discriminator"] === "ListValue") {
-            let result = new ListValue();
-            result.init(data);
-            return result;
-        }
-        throw new Error("The abstract class 'Value' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["discriminator"] = this._discriminator;
-        return data;
-    }
-}
-
-export interface IValue {
-}
-
-export class ErrorValue extends Value implements IErrorValue {
-    message?: string | undefined;
-
-    constructor(data?: IErrorValue) {
-        super(data);
-        this._discriminator = "ErrorValue";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.message = data["Message"];
-        }
-    }
-
-    static fromJS(data: any): ErrorValue {
-        data = typeof data === 'object' ? data : {};
-        let result = new ErrorValue();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Message"] = this.message;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IErrorValue extends IValue {
-    message?: string | undefined;
-}
-
-export class DoubleValue extends Value implements IDoubleValue {
-    value?: number | undefined;
-
-    constructor(data?: IDoubleValue) {
-        super(data);
-        this._discriminator = "DoubleValue";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.value = data["Value"];
-        }
-    }
-
-    static fromJS(data: any): DoubleValue {
-        data = typeof data === 'object' ? data : {};
-        let result = new DoubleValue();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Value"] = this.value;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IDoubleValue extends IValue {
-    value?: number | undefined;
-}
-
-export class LongValue extends Value implements ILongValue {
-    value?: number | undefined;
-
-    constructor(data?: ILongValue) {
-        super(data);
-        this._discriminator = "LongValue";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.value = data["Value"];
-        }
-    }
-
-    static fromJS(data: any): LongValue {
-        data = typeof data === 'object' ? data : {};
-        let result = new LongValue();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Value"] = this.value;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ILongValue extends IValue {
-    value?: number | undefined;
-}
-
-export class BoolValue extends Value implements IBoolValue {
-    value?: boolean | undefined;
-
-    constructor(data?: IBoolValue) {
-        super(data);
-        this._discriminator = "BoolValue";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.value = data["Value"];
-        }
-    }
-
-    static fromJS(data: any): BoolValue {
-        data = typeof data === 'object' ? data : {};
-        let result = new BoolValue();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Value"] = this.value;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IBoolValue extends IValue {
-    value?: boolean | undefined;
-}
-
-export class StringValue extends Value implements IStringValue {
-    value?: string | undefined;
-
-    constructor(data?: IStringValue) {
-        super(data);
-        this._discriminator = "StringValue";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.value = data["Value"];
-        }
-    }
-
-    static fromJS(data: any): StringValue {
-        data = typeof data === 'object' ? data : {};
-        let result = new StringValue();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Value"] = this.value;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IStringValue extends IValue {
-    value?: string | undefined;
-}
-
-export class DatasetUriValue extends Value implements IDatasetUriValue {
-    value?: string | undefined;
-
-    constructor(data?: IDatasetUriValue) {
-        super(data);
-        this._discriminator = "DatasetUriValue";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.value = data["Value"];
-        }
-    }
-
-    static fromJS(data: any): DatasetUriValue {
-        data = typeof data === 'object' ? data : {};
-        let result = new DatasetUriValue();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Value"] = this.value;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IDatasetUriValue extends IValue {
-    value?: string | undefined;
-}
-
-export class CsvUriValue extends Value implements ICsvUriValue {
-    value?: string | undefined;
-
-    constructor(data?: ICsvUriValue) {
-        super(data);
-        this._discriminator = "CsvUriValue";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.value = data["Value"];
-        }
-    }
-
-    static fromJS(data: any): CsvUriValue {
-        data = typeof data === 'object' ? data : {};
-        let result = new CsvUriValue();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Value"] = this.value;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ICsvUriValue extends IValue {
-    value?: string | undefined;
-}
-
-export class PickleUriValue extends Value implements IPickleUriValue {
-    value?: string | undefined;
-
-    constructor(data?: IPickleUriValue) {
-        super(data);
-        this._discriminator = "PickleUriValue";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.value = data["Value"];
-        }
-    }
-
-    static fromJS(data: any): PickleUriValue {
-        data = typeof data === 'object' ? data : {};
-        let result = new PickleUriValue();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Value"] = this.value;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IPickleUriValue extends IValue {
-    value?: string | undefined;
-}
-
-export class PickleBlobValue extends Value implements IPickleBlobValue {
-    value?: string | undefined;
-
-    constructor(data?: IPickleBlobValue) {
-        super(data);
-        this._discriminator = "PickleBlobValue";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.value = data["Value"];
-        }
-    }
-
-    static fromJS(data: any): PickleBlobValue {
-        data = typeof data === 'object' ? data : {};
-        let result = new PickleBlobValue();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Value"] = this.value;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IPickleBlobValue extends IValue {
-    value?: string | undefined;
-}
-
-export class PlasmaIdValue extends Value implements IPlasmaIdValue {
-    value?: string | undefined;
-
-    constructor(data?: IPlasmaIdValue) {
-        super(data);
-        this._discriminator = "PlasmaIdValue";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.value = data["Value"];
-        }
-    }
-
-    static fromJS(data: any): PlasmaIdValue {
-        data = typeof data === 'object' ? data : {};
-        let result = new PlasmaIdValue();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Value"] = this.value;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IPlasmaIdValue extends IValue {
-    value?: string | undefined;
-}
-
-export class BytesValue extends Value implements IBytesValue {
-    value?: string | undefined;
-
-    constructor(data?: IBytesValue) {
-        super(data);
-        this._discriminator = "BytesValue";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.value = data["Value"];
-        }
-    }
-
-    static fromJS(data: any): BytesValue {
-        data = typeof data === 'object' ? data : {};
-        let result = new BytesValue();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Value"] = this.value;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IBytesValue extends IValue {
-    value?: string | undefined;
-}
-
-export class ContainerArgument extends PrimitiveStepArgument implements IContainerArgument {
-    data?: string | undefined;
-
-    constructor(data?: IContainerArgument) {
-        super(data);
-        this._discriminator = "ContainerArgument";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.data = data["Data"];
-        }
-    }
-
-    static fromJS(data: any): ContainerArgument {
-        data = typeof data === 'object' ? data : {};
-        let result = new ContainerArgument();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Data"] = this.data;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IContainerArgument extends IPrimitiveStepArgument {
-    data?: string | undefined;
-}
-
-export class Score implements IScore {
-    metricType?: MetricType | undefined;
-    value?: number | undefined;
-
-    constructor(data?: IScore) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.metricType = data["MetricType"];
-            this.value = data["Value"];
-        }
-    }
-
-    static fromJS(data: any): Score {
-        data = typeof data === 'object' ? data : {};
-        let result = new Score();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["MetricType"] = this.metricType;
-        data["Value"] = this.value;
-        return data;
-    }
-}
-
-export interface IScore {
-    metricType?: MetricType | undefined;
-    value?: number | undefined;
-}
-
-export class ExampleResult extends Result implements IExampleResult {
-    resultValues?: { [key: string]: string; } | undefined;
-    message?: string | undefined;
-
-    constructor(data?: IExampleResult) {
-        super(data);
-        this._discriminator = "ExampleResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["ResultValues"]) {
-                this.resultValues = {};
-                for (let key in data["ResultValues"]) {
-                    if (data["ResultValues"].hasOwnProperty(key))
-                        this.resultValues[key] = data["ResultValues"][key];
-                }
-            }
-            this.message = data["Message"];
-        }
-    }
-
-    static fromJS(data: any): ExampleResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new ExampleResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.resultValues) {
-            data["ResultValues"] = {};
-            for (let key in this.resultValues) {
-                if (this.resultValues.hasOwnProperty(key))
-                    data["ResultValues"][key] = this.resultValues[key];
-            }
-        }
-        data["Message"] = this.message;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IExampleResult extends IResult {
-    resultValues?: { [key: string]: string; } | undefined;
-    message?: string | undefined;
-}
-
-export class NewModelOperationResult extends ModelOperationResult implements INewModelOperationResult {
-
-    constructor(data?: INewModelOperationResult) {
-        super(data);
-        this._discriminator = "NewModelOperationResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): NewModelOperationResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new NewModelOperationResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface INewModelOperationResult extends IModelOperationResult {
-}
-
-export class AddComparisonResult extends ModelOperationResult implements IAddComparisonResult {
-    comparisonId?: ComparisonId | undefined;
-
-    constructor(data?: IAddComparisonResult) {
-        super(data);
-        this._discriminator = "AddComparisonResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.comparisonId = data["ComparisonId"] ? ComparisonId.fromJS(data["ComparisonId"]) : <any>undefined;
-        }
-    }
-
-    static fromJS(data: any): AddComparisonResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new AddComparisonResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["ComparisonId"] = this.comparisonId ? this.comparisonId.toJSON() : <any>undefined;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IAddComparisonResult extends IModelOperationResult {
-    comparisonId?: ComparisonId | undefined;
-}
-
-export class GetModelStateResult extends ModelOperationResult implements IGetModelStateResult {
-    decisions?: Decision[] | undefined;
-    startingWealth?: number | undefined;
-    currentWealth?: number | undefined;
-
-    constructor(data?: IGetModelStateResult) {
-        super(data);
-        this._discriminator = "GetModelStateResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["Decisions"] && data["Decisions"].constructor === Array) {
-                this.decisions = [];
-                for (let item of data["Decisions"])
-                    this.decisions.push(Decision.fromJS(item));
-            }
-            this.startingWealth = data["StartingWealth"];
-            this.currentWealth = data["CurrentWealth"];
-        }
-    }
-
-    static fromJS(data: any): GetModelStateResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new GetModelStateResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.decisions && this.decisions.constructor === Array) {
-            data["Decisions"] = [];
-            for (let item of this.decisions)
-                data["Decisions"].push(item.toJSON());
-        }
-        data["StartingWealth"] = this.startingWealth;
-        data["CurrentWealth"] = this.currentWealth;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IGetModelStateResult extends IModelOperationResult {
-    decisions?: Decision[] | undefined;
-    startingWealth?: number | undefined;
-    currentWealth?: number | undefined;
-}
-
-export class AggregateKey implements IAggregateKey {
-    aggregateParameterIndex?: number | undefined;
-    brushIndex?: number | undefined;
-
-    constructor(data?: IAggregateKey) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.aggregateParameterIndex = data["AggregateParameterIndex"];
-            this.brushIndex = data["BrushIndex"];
-        }
-    }
-
-    static fromJS(data: any): AggregateKey {
-        data = typeof data === 'object' ? data : {};
-        let result = new AggregateKey();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["AggregateParameterIndex"] = this.aggregateParameterIndex;
-        data["BrushIndex"] = this.brushIndex;
-        return data;
-    }
-}
-
-export interface IAggregateKey {
-    aggregateParameterIndex?: number | undefined;
-    brushIndex?: number | undefined;
-}
-
-export abstract class IResult implements IIResult {
-
-    constructor(data?: IIResult) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): IResult {
-        data = typeof data === 'object' ? data : {};
-        throw new Error("The abstract class 'IResult' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        return data;
-    }
-}
-
-export interface IIResult {
-}
-
-export class DataArgument extends PrimitiveStepArgument implements IDataArgument {
-    data?: string | undefined;
-
-    constructor(data?: IDataArgument) {
-        super(data);
-        this._discriminator = "DataArgument";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.data = data["Data"];
-        }
-    }
-
-    static fromJS(data: any): DataArgument {
-        data = typeof data === 'object' ? data : {};
-        let result = new DataArgument();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Data"] = this.data;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IDataArgument extends IPrimitiveStepArgument {
-    data?: string | undefined;
-}
-
-export class ListValue extends Value implements IListValue {
-    items?: Value[] | undefined;
-
-    constructor(data?: IListValue) {
-        super(data);
-        this._discriminator = "ListValue";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["Items"] && data["Items"].constructor === Array) {
-                this.items = [];
-                for (let item of data["Items"])
-                    this.items.push(Value.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): ListValue {
-        data = typeof data === 'object' ? data : {};
-        let result = new ListValue();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.items && this.items.constructor === Array) {
-            data["Items"] = [];
-            for (let item of this.items)
-                data["Items"].push(item.toJSON());
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IListValue extends IValue {
-    items?: Value[] | undefined;
-}
-
-export class Metrics implements IMetrics {
-    averageAccuracy?: number | undefined;
-    averageRSquared?: number | undefined;
-    f1Macro?: number | undefined;
-
-    constructor(data?: IMetrics) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.averageAccuracy = data["AverageAccuracy"];
-            this.averageRSquared = data["AverageRSquared"];
-            this.f1Macro = data["F1Macro"];
-        }
-    }
-
-    static fromJS(data: any): Metrics {
-        data = typeof data === 'object' ? data : {};
-        let result = new Metrics();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["AverageAccuracy"] = this.averageAccuracy;
-        data["AverageRSquared"] = this.averageRSquared;
-        data["F1Macro"] = this.f1Macro;
-        return data;
-    }
-}
-
-export interface IMetrics {
-    averageAccuracy?: number | undefined;
-    averageRSquared?: number | undefined;
-    f1Macro?: number | undefined;
-}
-
-export class FeatureImportanceOperationParameters extends DistOperationParameters implements IFeatureImportanceOperationParameters {
-    solutionId?: string | undefined;
-
-    constructor(data?: IFeatureImportanceOperationParameters) {
-        super(data);
-        this._discriminator = "FeatureImportanceOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.solutionId = data["SolutionId"];
-        }
-    }
-
-    static fromJS(data: any): FeatureImportanceOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new FeatureImportanceOperationParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["SolutionId"] = this.solutionId;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IFeatureImportanceOperationParameters extends IDistOperationParameters {
-    solutionId?: string | undefined;
-}
-
-export class FeatureImportanceResult extends Result implements IFeatureImportanceResult {
-    featureImportances?: { [key: string]: TupleOfDoubleAndDouble; } | undefined;
-
-    constructor(data?: IFeatureImportanceResult) {
-        super(data);
-        this._discriminator = "FeatureImportanceResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["FeatureImportances"]) {
-                this.featureImportances = {};
-                for (let key in data["FeatureImportances"]) {
-                    if (data["FeatureImportances"].hasOwnProperty(key))
-                        this.featureImportances[key] = data["FeatureImportances"][key] ? TupleOfDoubleAndDouble.fromJS(data["FeatureImportances"][key]) : new TupleOfDoubleAndDouble();
-                }
-            }
-        }
-    }
-
-    static fromJS(data: any): FeatureImportanceResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new FeatureImportanceResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.featureImportances) {
-            data["FeatureImportances"] = {};
-            for (let key in this.featureImportances) {
-                if (this.featureImportances.hasOwnProperty(key))
-                    data["FeatureImportances"][key] = this.featureImportances[key];
-            }
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IFeatureImportanceResult extends IResult {
-    featureImportances?: { [key: string]: TupleOfDoubleAndDouble; } | undefined;
-}
-
-export class TupleOfDoubleAndDouble implements ITupleOfDoubleAndDouble {
-    item1?: number | undefined;
-    item2?: number | undefined;
-
-    constructor(data?: ITupleOfDoubleAndDouble) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.item1 = data["Item1"];
-            this.item2 = data["Item2"];
-        }
-    }
-
-    static fromJS(data: any): TupleOfDoubleAndDouble {
-        data = typeof data === 'object' ? data : {};
-        let result = new TupleOfDoubleAndDouble();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Item1"] = this.item1;
-        data["Item2"] = this.item2;
-        return data;
-    }
-}
-
-export interface ITupleOfDoubleAndDouble {
-    item1?: number | undefined;
-    item2?: number | undefined;
-}
-
-export class PrimitiveStepDescription extends StepDescription implements IPrimitiveStepDescription {
-    hyperparams?: { [key: string]: Value; } | undefined;
-
-    constructor(data?: IPrimitiveStepDescription) {
-        super(data);
-        this._discriminator = "PrimitiveStepDescription";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["Hyperparams"]) {
-                this.hyperparams = {};
-                for (let key in data["Hyperparams"]) {
-                    if (data["Hyperparams"].hasOwnProperty(key))
-                        this.hyperparams[key] = data["Hyperparams"][key] ? Value.fromJS(data["Hyperparams"][key]) : <any>undefined;
-                }
-            }
-        }
-    }
-
-    static fromJS(data: any): PrimitiveStepDescription {
-        data = typeof data === 'object' ? data : {};
-        let result = new PrimitiveStepDescription();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.hyperparams) {
-            data["Hyperparams"] = {};
-            for (let key in this.hyperparams) {
-                if (this.hyperparams.hasOwnProperty(key))
-                    data["Hyperparams"][key] = this.hyperparams[key];
-            }
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IPrimitiveStepDescription extends IStepDescription {
-    hyperparams?: { [key: string]: Value; } | undefined;
-}
-
-export enum ValueType {
-    VALUE_TYPE_UNDEFINED = 0,
-    RAW = 1,
-    DATASET_URI = 2,
-    CSV_URI = 3,
-    PICKLE_URI = 4,
-    PICKLE_BLOB = 5,
-    PLASMA_ID = 6,
-}
-
-export class DatamartSearchParameters implements IDatamartSearchParameters {
-    adapterName?: string | undefined;
-    queryJson?: string | undefined;
-
-    constructor(data?: IDatamartSearchParameters) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.adapterName = data["AdapterName"];
-            this.queryJson = data["QueryJson"];
-        }
-    }
-
-    static fromJS(data: any): DatamartSearchParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new DatamartSearchParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["AdapterName"] = this.adapterName;
-        data["QueryJson"] = this.queryJson;
-        return data;
-    }
-}
-
-export interface IDatamartSearchParameters {
-    adapterName?: string | undefined;
-    queryJson?: string | undefined;
-}
-
-export class DatamartAugmentParameters implements IDatamartAugmentParameters {
-    adapterName?: string | undefined;
-    augmentationJson?: string | undefined;
-    numberOfSamples?: number | undefined;
-    augmentedAdapterName?: string | undefined;
-
-    constructor(data?: IDatamartAugmentParameters) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.adapterName = data["AdapterName"];
-            this.augmentationJson = data["AugmentationJson"];
-            this.numberOfSamples = data["NumberOfSamples"];
-            this.augmentedAdapterName = data["AugmentedAdapterName"];
-        }
-    }
-
-    static fromJS(data: any): DatamartAugmentParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new DatamartAugmentParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["AdapterName"] = this.adapterName;
-        data["AugmentationJson"] = this.augmentationJson;
-        data["NumberOfSamples"] = this.numberOfSamples;
-        data["AugmentedAdapterName"] = this.augmentedAdapterName;
-        return data;
-    }
-}
-
-export interface IDatamartAugmentParameters {
-    adapterName?: string | undefined;
-    augmentationJson?: string | undefined;
-    numberOfSamples?: number | undefined;
-    augmentedAdapterName?: string | undefined;
-}
-
-export class RawDataResult extends DistResult implements IRawDataResult {
-    samples?: { [key: string]: any[]; } | undefined;
-    weightedWords?: { [key: string]: Word[]; } | undefined;
-
-    constructor(data?: IRawDataResult) {
-        super(data);
-        this._discriminator = "RawDataResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["Samples"]) {
-                this.samples = {};
-                for (let key in data["Samples"]) {
-                    if (data["Samples"].hasOwnProperty(key))
-                        this.samples[key] = data["Samples"][key] !== undefined ? data["Samples"][key] : [];
-                }
-            }
-            if (data["WeightedWords"]) {
-                this.weightedWords = {};
-                for (let key in data["WeightedWords"]) {
-                    if (data["WeightedWords"].hasOwnProperty(key))
-                        this.weightedWords[key] = data["WeightedWords"][key] ? data["WeightedWords"][key].map((i: any) => Word.fromJS(i)) : [];
-                }
-            }
-        }
-    }
-
-    static fromJS(data: any): RawDataResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new RawDataResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.samples) {
-            data["Samples"] = {};
-            for (let key in this.samples) {
-                if (this.samples.hasOwnProperty(key))
-                    data["Samples"][key] = this.samples[key];
-            }
-        }
-        if (this.weightedWords) {
-            data["WeightedWords"] = {};
-            for (let key in this.weightedWords) {
-                if (this.weightedWords.hasOwnProperty(key))
-                    data["WeightedWords"][key] = this.weightedWords[key];
-            }
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IRawDataResult extends IDistResult {
-    samples?: { [key: string]: any[]; } | undefined;
-    weightedWords?: { [key: string]: Word[]; } | undefined;
-}
-
-export class Word implements IWord {
-    text?: string | undefined;
-    occurrences?: number | undefined;
-    stem?: string | undefined;
-    isWordGroup?: boolean | undefined;
-
-    constructor(data?: IWord) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.text = data["Text"];
-            this.occurrences = data["Occurrences"];
-            this.stem = data["Stem"];
-            this.isWordGroup = data["IsWordGroup"];
-        }
-    }
-
-    static fromJS(data: any): Word {
-        data = typeof data === 'object' ? data : {};
-        let result = new Word();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Text"] = this.text;
-        data["Occurrences"] = this.occurrences;
-        data["Stem"] = this.stem;
-        data["IsWordGroup"] = this.isWordGroup;
-        return data;
-    }
-}
-
-export interface IWord {
-    text?: string | undefined;
-    occurrences?: number | undefined;
-    stem?: string | undefined;
-    isWordGroup?: boolean | undefined;
-}
-
-export class SampleOperationParameters extends DistOperationParameters implements ISampleOperationParameters {
-    numSamples?: number | undefined;
-    attributeParameters?: AttributeParameters[] | undefined;
-    brushes?: string[] | undefined;
-
-    constructor(data?: ISampleOperationParameters) {
-        super(data);
-        this._discriminator = "SampleOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.numSamples = data["NumSamples"];
-            if (data["AttributeParameters"] && data["AttributeParameters"].constructor === Array) {
-                this.attributeParameters = [];
-                for (let item of data["AttributeParameters"])
-                    this.attributeParameters.push(AttributeParameters.fromJS(item));
-            }
-            if (data["Brushes"] && data["Brushes"].constructor === Array) {
-                this.brushes = [];
-                for (let item of data["Brushes"])
-                    this.brushes.push(item);
-            }
-        }
-    }
-
-    static fromJS(data: any): SampleOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new SampleOperationParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["NumSamples"] = this.numSamples;
-        if (this.attributeParameters && this.attributeParameters.constructor === Array) {
-            data["AttributeParameters"] = [];
-            for (let item of this.attributeParameters)
-                data["AttributeParameters"].push(item.toJSON());
-        }
-        if (this.brushes && this.brushes.constructor === Array) {
-            data["Brushes"] = [];
-            for (let item of this.brushes)
-                data["Brushes"].push(item);
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ISampleOperationParameters extends IDistOperationParameters {
-    numSamples?: number | undefined;
-    attributeParameters?: AttributeParameters[] | undefined;
-    brushes?: string[] | undefined;
-}
-
-export class SampleResult extends DistResult implements ISampleResult {
-    samples?: { [key: string]: { [key: string]: number; }; } | undefined;
-    isTruncated?: boolean | undefined;
-
-    constructor(data?: ISampleResult) {
-        super(data);
-        this._discriminator = "SampleResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["Samples"]) {
-                this.samples = {};
-                for (let key in data["Samples"]) {
-                    if (data["Samples"].hasOwnProperty(key))
-                        this.samples[key] = data["Samples"][key] !== undefined ? data["Samples"][key] : {};
-                }
-            }
-            this.isTruncated = data["IsTruncated"];
-        }
-    }
-
-    static fromJS(data: any): SampleResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new SampleResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.samples) {
-            data["Samples"] = {};
-            for (let key in this.samples) {
-                if (this.samples.hasOwnProperty(key))
-                    data["Samples"][key] = this.samples[key];
-            }
-        }
-        data["IsTruncated"] = this.isTruncated;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ISampleResult extends IDistResult {
-    samples?: { [key: string]: { [key: string]: number; }; } | undefined;
-    isTruncated?: boolean | undefined;
-}
-
-export class ResultParameters extends UniqueJson implements IResultParameters {
-    operationReference?: IOperationReference | undefined;
-    stopOperation?: boolean | undefined;
-
-    protected _discriminator: string;
-
-    constructor(data?: IResultParameters) {
-        super(data);
-        this._discriminator = "ResultParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.operationReference = data["OperationReference"] ? IOperationReference.fromJS(data["OperationReference"]) : <any>undefined;
-            this.stopOperation = data["StopOperation"];
-        }
-    }
-
-    static fromJS(data: any): ResultParameters {
-        data = typeof data === 'object' ? data : {};
-        if (data["discriminator"] === "RecommenderResultParameters") {
-            let result = new RecommenderResultParameters();
-            result.init(data);
-            return result;
-        }
-        let result = new ResultParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["discriminator"] = this._discriminator;
-        data["OperationReference"] = this.operationReference ? this.operationReference.toJSON() : <any>undefined;
-        data["StopOperation"] = this.stopOperation;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IResultParameters extends IUniqueJson {
-    operationReference?: IOperationReference | undefined;
-    stopOperation?: boolean | undefined;
-}
-
-export class RecommenderResultParameters extends ResultParameters implements IRecommenderResultParameters {
-    from?: number | undefined;
-    to?: number | undefined;
-    pValueSorting?: Sorting | undefined;
-    effectSizeFilter?: EffectSize | undefined;
-
-    constructor(data?: IRecommenderResultParameters) {
-        super(data);
-        this._discriminator = "RecommenderResultParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.from = data["From"];
-            this.to = data["To"];
-            this.pValueSorting = data["PValueSorting"];
-            this.effectSizeFilter = data["EffectSizeFilter"];
-        }
-    }
-
-    static fromJS(data: any): RecommenderResultParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new RecommenderResultParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["From"] = this.from;
-        data["To"] = this.to;
-        data["PValueSorting"] = this.pValueSorting;
-        data["EffectSizeFilter"] = this.effectSizeFilter;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IRecommenderResultParameters extends IResultParameters {
-    from?: number | undefined;
-    to?: number | undefined;
-    pValueSorting?: Sorting | undefined;
-    effectSizeFilter?: EffectSize | undefined;
-}
-
-export enum Sorting {
-    Ascending = "Ascending",
-    Descending = "Descending",
-}
-
-export class AddComparisonParameters extends ModelOperationParameters implements IAddComparisonParameters {
-    modelId?: ModelId | undefined;
-    comparisonOrder?: number | undefined;
-    childOperationParameters?: OperationParameters[] | undefined;
-    isCachable?: boolean | undefined;
-
-    constructor(data?: IAddComparisonParameters) {
-        super(data);
-        this._discriminator = "AddComparisonParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.modelId = data["ModelId"] ? ModelId.fromJS(data["ModelId"]) : <any>undefined;
-            this.comparisonOrder = data["ComparisonOrder"];
-            if (data["ChildOperationParameters"] && data["ChildOperationParameters"].constructor === Array) {
-                this.childOperationParameters = [];
-                for (let item of data["ChildOperationParameters"])
-                    this.childOperationParameters.push(OperationParameters.fromJS(item));
-            }
-            this.isCachable = data["IsCachable"];
-        }
-    }
-
-    static fromJS(data: any): AddComparisonParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new AddComparisonParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["ModelId"] = this.modelId ? this.modelId.toJSON() : <any>undefined;
-        data["ComparisonOrder"] = this.comparisonOrder;
-        if (this.childOperationParameters && this.childOperationParameters.constructor === Array) {
-            data["ChildOperationParameters"] = [];
-            for (let item of this.childOperationParameters)
-                data["ChildOperationParameters"].push(item.toJSON());
-        }
-        data["IsCachable"] = this.isCachable;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IAddComparisonParameters extends IModelOperationParameters {
-    modelId?: ModelId | undefined;
-    comparisonOrder?: number | undefined;
-    childOperationParameters?: OperationParameters[] | undefined;
-    isCachable?: boolean | undefined;
-}
-
-export class CDFResult extends DistResult implements ICDFResult {
-    cDF?: { [key: string]: number; } | undefined;
-
-    constructor(data?: ICDFResult) {
-        super(data);
-        this._discriminator = "CDFResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["CDF"]) {
-                this.cDF = {};
-                for (let key in data["CDF"]) {
-                    if (data["CDF"].hasOwnProperty(key))
-                        this.cDF[key] = data["CDF"][key];
-                }
-            }
-        }
-    }
-
-    static fromJS(data: any): CDFResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new CDFResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.cDF) {
-            data["CDF"] = {};
-            for (let key in this.cDF) {
-                if (this.cDF.hasOwnProperty(key))
-                    data["CDF"][key] = this.cDF[key];
-            }
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ICDFResult extends IDistResult {
-    cDF?: { [key: string]: number; } | undefined;
-}
-
-export class ChiSquaredTestResult extends HypothesisTestResult implements IChiSquaredTestResult {
-    hs_aligned?: TupleOfDoubleAndDouble[] | undefined;
-
-    constructor(data?: IChiSquaredTestResult) {
-        super(data);
-        this._discriminator = "ChiSquaredTestResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["hs_aligned"] && data["hs_aligned"].constructor === Array) {
-                this.hs_aligned = [];
-                for (let item of data["hs_aligned"])
-                    this.hs_aligned.push(TupleOfDoubleAndDouble.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): ChiSquaredTestResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new ChiSquaredTestResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.hs_aligned && this.hs_aligned.constructor === Array) {
-            data["hs_aligned"] = [];
-            for (let item of this.hs_aligned)
-                data["hs_aligned"].push(item.toJSON());
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IChiSquaredTestResult extends IHypothesisTestResult {
-    hs_aligned?: TupleOfDoubleAndDouble[] | undefined;
-}
-
-export class CorrelationTestResult extends HypothesisTestResult implements ICorrelationTestResult {
-    degreeOfFreedom?: number | undefined;
-    sampleCorrelationCoefficient?: number | undefined;
-    distResult?: EmpiricalDistResult | undefined;
-
-    constructor(data?: ICorrelationTestResult) {
-        super(data);
-        this._discriminator = "CorrelationTestResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.degreeOfFreedom = data["DegreeOfFreedom"];
-            this.sampleCorrelationCoefficient = data["SampleCorrelationCoefficient"];
-            this.distResult = data["DistResult"] ? EmpiricalDistResult.fromJS(data["DistResult"]) : <any>undefined;
-        }
-    }
-
-    static fromJS(data: any): CorrelationTestResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new CorrelationTestResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["DegreeOfFreedom"] = this.degreeOfFreedom;
-        data["SampleCorrelationCoefficient"] = this.sampleCorrelationCoefficient;
-        data["DistResult"] = this.distResult ? this.distResult.toJSON() : <any>undefined;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ICorrelationTestResult extends IHypothesisTestResult {
-    degreeOfFreedom?: number | undefined;
-    sampleCorrelationCoefficient?: number | undefined;
-    distResult?: EmpiricalDistResult | undefined;
-}
-
-export class EmpiricalDistResult extends DistResult implements IEmpiricalDistResult {
-    marginals?: AttributeParameters[] | undefined;
-    marginalDistParameters?: { [key: string]: DistParameter; } | undefined;
-    jointDistParameter?: JointDistParameter | undefined;
-
-    constructor(data?: IEmpiricalDistResult) {
-        super(data);
-        this._discriminator = "EmpiricalDistResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["Marginals"] && data["Marginals"].constructor === Array) {
-                this.marginals = [];
-                for (let item of data["Marginals"])
-                    this.marginals.push(AttributeParameters.fromJS(item));
-            }
-            if (data["MarginalDistParameters"]) {
-                this.marginalDistParameters = {};
-                for (let key in data["MarginalDistParameters"]) {
-                    if (data["MarginalDistParameters"].hasOwnProperty(key))
-                        this.marginalDistParameters[key] = data["MarginalDistParameters"][key] ? DistParameter.fromJS(data["MarginalDistParameters"][key]) : new DistParameter();
-                }
-            }
-            this.jointDistParameter = data["JointDistParameter"] ? JointDistParameter.fromJS(data["JointDistParameter"]) : <any>undefined;
-        }
-    }
-
-    static fromJS(data: any): EmpiricalDistResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new EmpiricalDistResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.marginals && this.marginals.constructor === Array) {
-            data["Marginals"] = [];
-            for (let item of this.marginals)
-                data["Marginals"].push(item.toJSON());
-        }
-        if (this.marginalDistParameters) {
-            data["MarginalDistParameters"] = {};
-            for (let key in this.marginalDistParameters) {
-                if (this.marginalDistParameters.hasOwnProperty(key))
-                    data["MarginalDistParameters"][key] = this.marginalDistParameters[key];
-            }
-        }
-        data["JointDistParameter"] = this.jointDistParameter ? this.jointDistParameter.toJSON() : <any>undefined;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IEmpiricalDistResult extends IDistResult {
-    marginals?: AttributeParameters[] | undefined;
-    marginalDistParameters?: { [key: string]: DistParameter; } | undefined;
-    jointDistParameter?: JointDistParameter | undefined;
-}
-
-export class DistParameter implements IDistParameter {
-    mean?: number | undefined;
-    moment2?: number | undefined;
-    variance?: number | undefined;
-    varianceEstimate?: number | undefined;
-    min?: number | undefined;
-    max?: number | undefined;
-
-    constructor(data?: IDistParameter) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.mean = data["Mean"];
-            this.moment2 = data["Moment2"];
-            this.variance = data["Variance"];
-            this.varianceEstimate = data["VarianceEstimate"];
-            this.min = data["Min"];
-            this.max = data["Max"];
-        }
-    }
-
-    static fromJS(data: any): DistParameter {
-        data = typeof data === 'object' ? data : {};
-        let result = new DistParameter();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Mean"] = this.mean;
-        data["Moment2"] = this.moment2;
-        data["Variance"] = this.variance;
-        data["VarianceEstimate"] = this.varianceEstimate;
-        data["Min"] = this.min;
-        data["Max"] = this.max;
-        return data;
-    }
-}
-
-export interface IDistParameter {
-    mean?: number | undefined;
-    moment2?: number | undefined;
-    variance?: number | undefined;
-    varianceEstimate?: number | undefined;
-    min?: number | undefined;
-    max?: number | undefined;
-}
-
-export class JointDistParameter implements IJointDistParameter {
-    jointDist?: DistParameter | undefined;
-    covariance?: number | undefined;
-
-    constructor(data?: IJointDistParameter) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.jointDist = data["JointDist"] ? DistParameter.fromJS(data["JointDist"]) : <any>undefined;
-            this.covariance = data["Covariance"];
-        }
-    }
-
-    static fromJS(data: any): JointDistParameter {
-        data = typeof data === 'object' ? data : {};
-        let result = new JointDistParameter();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["JointDist"] = this.jointDist ? this.jointDist.toJSON() : <any>undefined;
-        data["Covariance"] = this.covariance;
-        return data;
-    }
-}
-
-export interface IJointDistParameter {
-    jointDist?: DistParameter | undefined;
-    covariance?: number | undefined;
-}
-
-export enum DistributionType {
-    Continuous = 0,
-    Discrete = 1,
-}
-
-export abstract class DistributionTypeExtension implements IDistributionTypeExtension {
-
-    constructor(data?: IDistributionTypeExtension) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): DistributionTypeExtension {
-        data = typeof data === 'object' ? data : {};
-        throw new Error("The abstract class 'DistributionTypeExtension' cannot be instantiated.");
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        return data;
-    }
-}
-
-export interface IDistributionTypeExtension {
-}
-
-export class GetModelStateParameters extends ModelOperationParameters implements IGetModelStateParameters {
-    modelId?: ModelId | undefined;
-    comparisonIds?: ComparisonId[] | undefined;
-    riskControlType?: RiskControlType | undefined;
-
-    constructor(data?: IGetModelStateParameters) {
-        super(data);
-        this._discriminator = "GetModelStateParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.modelId = data["ModelId"] ? ModelId.fromJS(data["ModelId"]) : <any>undefined;
-            if (data["ComparisonIds"] && data["ComparisonIds"].constructor === Array) {
-                this.comparisonIds = [];
-                for (let item of data["ComparisonIds"])
-                    this.comparisonIds.push(ComparisonId.fromJS(item));
-            }
-            this.riskControlType = data["RiskControlType"];
-        }
-    }
-
-    static fromJS(data: any): GetModelStateParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new GetModelStateParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["ModelId"] = this.modelId ? this.modelId.toJSON() : <any>undefined;
-        if (this.comparisonIds && this.comparisonIds.constructor === Array) {
-            data["ComparisonIds"] = [];
-            for (let item of this.comparisonIds)
-                data["ComparisonIds"].push(item.toJSON());
-        }
-        data["RiskControlType"] = this.riskControlType;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IGetModelStateParameters extends IModelOperationParameters {
-    modelId?: ModelId | undefined;
-    comparisonIds?: ComparisonId[] | undefined;
-    riskControlType?: RiskControlType | undefined;
-}
-
-export class KSTestResult extends HypothesisTestResult implements IKSTestResult {
-
-    constructor(data?: IKSTestResult) {
-        super(data);
-        this._discriminator = "KSTestResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): KSTestResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new KSTestResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IKSTestResult extends IHypothesisTestResult {
-}
-
-export class ModelWealthParameters extends UniqueJson implements IModelWealthParameters {
-    modelId?: ModelId | undefined;
-    riskControlType?: RiskControlType | undefined;
-
-    constructor(data?: IModelWealthParameters) {
-        super(data);
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.modelId = data["ModelId"] ? ModelId.fromJS(data["ModelId"]) : <any>undefined;
-            this.riskControlType = data["RiskControlType"];
-        }
-    }
-
-    static fromJS(data: any): ModelWealthParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new ModelWealthParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["ModelId"] = this.modelId ? this.modelId.toJSON() : <any>undefined;
-        data["RiskControlType"] = this.riskControlType;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IModelWealthParameters extends IUniqueJson {
-    modelId?: ModelId | undefined;
-    riskControlType?: RiskControlType | undefined;
-}
-
-export class RootMeanSquareTestResult extends HypothesisTestResult implements IRootMeanSquareTestResult {
-    simulationCount?: number | undefined;
-    extremeSimulationCount?: number | undefined;
-
-    constructor(data?: IRootMeanSquareTestResult) {
-        super(data);
-        this._discriminator = "RootMeanSquareTestResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.simulationCount = data["SimulationCount"];
-            this.extremeSimulationCount = data["ExtremeSimulationCount"];
-        }
-    }
-
-    static fromJS(data: any): RootMeanSquareTestResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new RootMeanSquareTestResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["SimulationCount"] = this.simulationCount;
-        data["ExtremeSimulationCount"] = this.extremeSimulationCount;
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IRootMeanSquareTestResult extends IHypothesisTestResult {
-    simulationCount?: number | undefined;
-    extremeSimulationCount?: number | undefined;
-}
-
-export class TTestResult extends HypothesisTestResult implements ITTestResult {
-    degreeOfFreedom?: number | undefined;
-    distResults?: EmpiricalDistResult[] | undefined;
-
-    constructor(data?: ITTestResult) {
-        super(data);
-        this._discriminator = "TTestResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.degreeOfFreedom = data["DegreeOfFreedom"];
-            if (data["DistResults"] && data["DistResults"].constructor === Array) {
-                this.distResults = [];
-                for (let item of data["DistResults"])
-                    this.distResults.push(EmpiricalDistResult.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): TTestResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new TTestResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["DegreeOfFreedom"] = this.degreeOfFreedom;
-        if (this.distResults && this.distResults.constructor === Array) {
-            data["DistResults"] = [];
-            for (let item of this.distResults)
-                data["DistResults"].push(item.toJSON());
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface ITTestResult extends IHypothesisTestResult {
-    degreeOfFreedom?: number | undefined;
-    distResults?: EmpiricalDistResult[] | undefined;
-}
-
-export enum Sorting2 {
-    Ascending = 0,
-    Descending = 1,
-}
-
-export class BinLabel implements IBinLabel {
-    value?: number | undefined;
-    minValue?: number | undefined;
-    maxValue?: number | undefined;
-    label?: string | undefined;
-
-    constructor(data?: IBinLabel) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.value = data["Value"];
-            this.minValue = data["MinValue"];
-            this.maxValue = data["MaxValue"];
-            this.label = data["Label"];
-        }
-    }
-
-    static fromJS(data: any): BinLabel {
-        data = typeof data === 'object' ? data : {};
-        let result = new BinLabel();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Value"] = this.value;
-        data["MinValue"] = this.minValue;
-        data["MaxValue"] = this.maxValue;
-        data["Label"] = this.label;
-        return data;
-    }
-}
-
-export interface IBinLabel {
-    value?: number | undefined;
-    minValue?: number | undefined;
-    maxValue?: number | undefined;
-    label?: string | undefined;
-}
-
-export class PreProcessedString implements IPreProcessedString {
-    value?: string | undefined;
-    id?: number | undefined;
-    stringLookup?: { [key: string]: number; } | undefined;
-    indexLookup?: { [key: string]: string; } | undefined;
-
-    constructor(data?: IPreProcessedString) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.value = data["Value"];
-            this.id = data["Id"];
-            if (data["StringLookup"]) {
-                this.stringLookup = {};
-                for (let key in data["StringLookup"]) {
-                    if (data["StringLookup"].hasOwnProperty(key))
-                        this.stringLookup[key] = data["StringLookup"][key];
-                }
-            }
-            if (data["IndexLookup"]) {
-                this.indexLookup = {};
-                for (let key in data["IndexLookup"]) {
-                    if (data["IndexLookup"].hasOwnProperty(key))
-                        this.indexLookup[key] = data["IndexLookup"][key];
-                }
-            }
-        }
-    }
-
-    static fromJS(data: any): PreProcessedString {
-        data = typeof data === 'object' ? data : {};
-        let result = new PreProcessedString();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Value"] = this.value;
-        data["Id"] = this.id;
-        if (this.stringLookup) {
-            data["StringLookup"] = {};
-            for (let key in this.stringLookup) {
-                if (this.stringLookup.hasOwnProperty(key))
-                    data["StringLookup"][key] = this.stringLookup[key];
-            }
-        }
-        if (this.indexLookup) {
-            data["IndexLookup"] = {};
-            for (let key in this.indexLookup) {
-                if (this.indexLookup.hasOwnProperty(key))
-                    data["IndexLookup"][key] = this.indexLookup[key];
-            }
-        }
-        return data;
-    }
-}
-
-export interface IPreProcessedString {
-    value?: string | undefined;
-    id?: number | undefined;
-    stringLookup?: { [key: string]: number; } | undefined;
-    indexLookup?: { [key: string]: string; } | undefined;
-}
-
-export class BitSet implements IBitSet {
-    length?: number | undefined;
-    size?: number | undefined;
-
-    constructor(data?: IBitSet) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-            this.length = data["Length"];
-            this.size = data["Size"];
-        }
-    }
-
-    static fromJS(data: any): BitSet {
-        data = typeof data === 'object' ? data : {};
-        let result = new BitSet();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Length"] = this.length;
-        data["Size"] = this.size;
-        return data;
-    }
-}
-
-export interface IBitSet {
-    length?: number | undefined;
-    size?: number | undefined;
-}
-
-export class DateTimeUtil implements IDateTimeUtil {
-
-    constructor(data?: IDateTimeUtil) {
-        if (data) {
-            for (var property in data) {
-                if (data.hasOwnProperty(property))
-                    (<any>this)[property] = (<any>data)[property];
-            }
-        }
-    }
-
-    init(data?: any) {
-        if (data) {
-        }
-    }
-
-    static fromJS(data: any): DateTimeUtil {
-        data = typeof data === 'object' ? data : {};
-        let result = new DateTimeUtil();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        return data;
-    }
-}
-
-export interface IDateTimeUtil {
-}
-
-export class FrequentItemsetOperationParameters extends DistOperationParameters implements IFrequentItemsetOperationParameters {
-    filter?: string | undefined;
-    attributeParameters?: AttributeParameters[] | undefined;
-    attributeCodeParameters?: AttributeCaclculatedParameters[] | undefined;
-
-    constructor(data?: IFrequentItemsetOperationParameters) {
-        super(data);
-        this._discriminator = "FrequentItemsetOperationParameters";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            this.filter = data["Filter"];
-            if (data["AttributeParameters"] && data["AttributeParameters"].constructor === Array) {
-                this.attributeParameters = [];
-                for (let item of data["AttributeParameters"])
-                    this.attributeParameters.push(AttributeParameters.fromJS(item));
-            }
-            if (data["AttributeCodeParameters"] && data["AttributeCodeParameters"].constructor === Array) {
-                this.attributeCodeParameters = [];
-                for (let item of data["AttributeCodeParameters"])
-                    this.attributeCodeParameters.push(AttributeCaclculatedParameters.fromJS(item));
-            }
-        }
-    }
-
-    static fromJS(data: any): FrequentItemsetOperationParameters {
-        data = typeof data === 'object' ? data : {};
-        let result = new FrequentItemsetOperationParameters();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        data["Filter"] = this.filter;
-        if (this.attributeParameters && this.attributeParameters.constructor === Array) {
-            data["AttributeParameters"] = [];
-            for (let item of this.attributeParameters)
-                data["AttributeParameters"].push(item.toJSON());
-        }
-        if (this.attributeCodeParameters && this.attributeCodeParameters.constructor === Array) {
-            data["AttributeCodeParameters"] = [];
-            for (let item of this.attributeCodeParameters)
-                data["AttributeCodeParameters"].push(item.toJSON());
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IFrequentItemsetOperationParameters extends IDistOperationParameters {
-    filter?: string | undefined;
-    attributeParameters?: AttributeParameters[] | undefined;
-    attributeCodeParameters?: AttributeCaclculatedParameters[] | undefined;
-}
-
-export class FrequentItemsetResult extends Result implements IFrequentItemsetResult {
-    frequentItems?: { [key: string]: number; } | undefined;
-
-    constructor(data?: IFrequentItemsetResult) {
-        super(data);
-        this._discriminator = "FrequentItemsetResult";
-    }
-
-    init(data?: any) {
-        super.init(data);
-        if (data) {
-            if (data["FrequentItems"]) {
-                this.frequentItems = {};
-                for (let key in data["FrequentItems"]) {
-                    if (data["FrequentItems"].hasOwnProperty(key))
-                        this.frequentItems[key] = data["FrequentItems"][key];
-                }
-            }
-        }
-    }
-
-    static fromJS(data: any): FrequentItemsetResult {
-        data = typeof data === 'object' ? data : {};
-        let result = new FrequentItemsetResult();
-        result.init(data);
-        return result;
-    }
-
-    toJSON(data?: any) {
-        data = typeof data === 'object' ? data : {};
-        if (this.frequentItems) {
-            data["FrequentItems"] = {};
-            for (let key in this.frequentItems) {
-                if (this.frequentItems.hasOwnProperty(key))
-                    data["FrequentItems"][key] = this.frequentItems[key];
-            }
-        }
-        super.toJSON(data);
-        return data;
-    }
-}
-
-export interface IFrequentItemsetResult extends IResult {
-    frequentItems?: { [key: string]: number; } | undefined;
-}
-
diff --git a/src/client/northstar/operations/BaseOperation.ts b/src/client/northstar/operations/BaseOperation.ts
deleted file mode 100644
index 013f2244e..000000000
--- a/src/client/northstar/operations/BaseOperation.ts
+++ /dev/null
@@ -1,162 +0,0 @@
-import { FilterModel } from '../core/filter/FilterModel';
-import { ErrorResult, Exception, OperationParameters, OperationReference, Result, ResultParameters } from '../model/idea/idea';
-import { action, computed, observable } from "mobx";
-import { Gateway } from '../manager/Gateway';
-
-export abstract class BaseOperation {
-    private _interactionTimeoutId: number = 0;
-    private static _currentOperations: Map<number, PollPromise> = new Map<number, PollPromise>();
-    //public InteractionTimeout: EventDelegate<InteractionTimeoutEventArgs> = new EventDelegate<InteractionTimeoutEventArgs>();
-
-    @observable public Error: string = "";
-    @observable public OverridingFilters: FilterModel[] = [];
-    //@observable 
-    @observable public Result?: Result = undefined;
-    @observable public ComputationStarted: boolean = false;
-    public OperationReference?: OperationReference = undefined;
-
-    private static _nextId = 0;
-    public RequestSalt: string = "";
-    public Id: number;
-
-    constructor() {
-        this.Id = BaseOperation._nextId++;
-    }
-
-    @computed
-    public get FilterString(): string {
-        return "";
-    }
-
-
-    @action
-    public SetResult(result: Result): void {
-        this.Result = result;
-    }
-
-    public async Update(): Promise<void> {
-
-        try {
-            if (BaseOperation._currentOperations.has(this.Id)) {
-                BaseOperation._currentOperations.get(this.Id)!.Cancel();
-                if (this.OperationReference) {
-                    Gateway.Instance.PauseOperation(this.OperationReference.toJSON());
-                }
-            }
-
-            const operationParameters = this.CreateOperationParameters();
-            if (this.Result) {
-                this.Result.progress = 0;
-            } // bcz: used to set Result to undefined, but that causes the display to blink
-            this.Error = "";
-            const salt = Math.random().toString();
-            this.RequestSalt = salt;
-
-            if (!operationParameters) {
-                this.ComputationStarted = false;
-                return;
-            }
-
-            this.ComputationStarted = true;
-            //let start = performance.now();
-            const promise = Gateway.Instance.StartOperation(operationParameters.toJSON());
-            promise.catch(err => {
-                action(() => {
-                    this.Error = err;
-                    console.error(err);
-                });
-            });
-            const operationReference = await promise;
-
-
-            if (operationReference) {
-                this.OperationReference = operationReference;
-
-                const resultParameters = new ResultParameters();
-                resultParameters.operationReference = operationReference;
-
-                const pollPromise = new PollPromise(salt, operationReference);
-                BaseOperation._currentOperations.set(this.Id, pollPromise);
-
-                pollPromise.Start(async () => {
-                    const result = await Gateway.Instance.GetResult(resultParameters.toJSON());
-                    if (result instanceof ErrorResult) {
-                        throw new Error((result).message);
-                    }
-                    if (this.RequestSalt === pollPromise.RequestSalt) {
-                        if (result && (!this.Result || this.Result.progress !== result.progress)) {
-                            /*if (operationViewModel.Result !== null && operationViewModel.Result !== undefined) {
-                                let t1 = performance.now();
-                                console.log((t1 - start) + " milliseconds.");
-                                start = performance.now();
-                            }*/
-                            this.SetResult(result);
-                        }
-
-                        if (!result || result.progress! < 1) {
-                            return true;
-                        }
-                    }
-                    return false;
-                }, 100).catch((err: Error) => action(() => {
-                    this.Error = err.message;
-                    console.error(err.message);
-                })()
-                );
-            }
-        }
-        catch (err) {
-            console.error(err as Exception);
-            // ErrorDialog.Instance.HandleError(err, operationViewModel);
-        }
-    }
-
-    public CreateOperationParameters(): OperationParameters | undefined { return undefined; }
-
-    private interactionTimeout() {
-        // clearTimeout(this._interactionTimeoutId);
-        // this.InteractionTimeout.Fire(new InteractionTimeoutEventArgs(this.TypedViewModel, InteractionTimeoutType.Timeout));
-    }
-}
-
-export class PollPromise {
-    public RequestSalt: string;
-    public OperationReference: OperationReference;
-
-    private _notCanceled: boolean = true;
-    private _poll: undefined | (() => Promise<boolean>);
-    private _delay: number = 0;
-
-    public constructor(requestKey: string, operationReference: OperationReference) {
-        this.RequestSalt = requestKey;
-        this.OperationReference = operationReference;
-    }
-
-    public Cancel(): void {
-        this._notCanceled = false;
-    }
-
-    public Start(poll: () => Promise<boolean>, delay: number): Promise<void> {
-        this._poll = poll;
-        this._delay = delay;
-        return this.pollRecursive();
-    }
-
-    private pollRecursive = (): Promise<void> => {
-        return Promise.resolve().then(this._poll).then((flag) => {
-            this._notCanceled && flag && new Promise((res) => (setTimeout(res, this._delay)))
-                .then(this.pollRecursive);
-        });
-    }
-}
-
-
-export class InteractionTimeoutEventArgs {
-    constructor(public Sender: object, public Type: InteractionTimeoutType) {
-    }
-}
-
-export enum InteractionTimeoutType {
-    Reset = 0,
-    Timeout = 1
-}
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
deleted file mode 100644
index 74e23ea48..000000000
--- a/src/client/northstar/operations/HistogramOperation.ts
+++ /dev/null
@@ -1,158 +0,0 @@
-import { action, computed, observable, trace } from "mobx";
-import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
-import { ColumnAttributeModel } from "../core/attribute/AttributeModel";
-import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
-import { CalculatedAttributeManager } from "../core/attribute/CalculatedAttributeModel";
-import { FilterModel } from "../core/filter/FilterModel";
-import { FilterOperand } from "../core/filter/FilterOperand";
-import { IBaseFilterConsumer } from "../core/filter/IBaseFilterConsumer";
-import { IBaseFilterProvider } from "../core/filter/IBaseFilterProvider";
-import { HistogramField } from "../dash-fields/HistogramField";
-import { SETTINGS_SAMPLE_SIZE, SETTINGS_X_BINS, SETTINGS_Y_BINS } from "../model/binRanges/VisualBinRangeHelper";
-import { AggregateFunction, AggregateParameters, Attribute, AverageAggregateParameters, Bin, DataType, DoubleValueAggregateResult, HistogramOperationParameters, HistogramResult, QuantitativeBinRange } from "../model/idea/idea";
-import { ModelHelpers } from "../model/ModelHelpers";
-import { ArrayUtil } from "../utils/ArrayUtil";
-import { BaseOperation } from "./BaseOperation";
-import { Doc } from "../../../new_fields/Doc";
-import { Cast, NumCast } from "../../../new_fields/Types";
-
-export class HistogramOperation extends BaseOperation implements IBaseFilterConsumer, IBaseFilterProvider {
-    public static Empty = new HistogramOperation("-empty schema-", new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())));
-    @observable public FilterOperand: FilterOperand = FilterOperand.AND;
-    @observable public Links: Doc[] = [];
-    @observable public BrushLinks: { l: Doc, b: Doc }[] = [];
-    @observable public BrushColors: number[] = [];
-    @observable public BarFilterModels: FilterModel[] = [];
-
-    @observable public Normalization: number = -1;
-    @observable public X: AttributeTransformationModel;
-    @observable public Y: AttributeTransformationModel;
-    @observable public V: AttributeTransformationModel;
-    @observable public SchemaName: string;
-    @observable public QRange: QuantitativeBinRange | undefined;
-    public get Schema() { return CurrentUserUtils.GetNorthstarSchema(this.SchemaName); }
-
-    constructor(schemaName: string, x: AttributeTransformationModel, y: AttributeTransformationModel, v: AttributeTransformationModel, normalized?: number) {
-        super();
-        this.X = x;
-        this.Y = y;
-        this.V = v;
-        this.Normalization = normalized ? normalized : -1;
-        this.SchemaName = schemaName;
-    }
-
-    public static Duplicate(op: HistogramOperation) {
-
-        return new HistogramOperation(op.SchemaName, op.X, op.Y, op.V, op.Normalization);
-    }
-    public Copy(): HistogramOperation {
-        return new HistogramOperation(this.SchemaName, this.X, this.Y, this.V, this.Normalization);
-    }
-
-    Equals(other: Object): boolean {
-        throw new Error("Method not implemented.");
-    }
-
-
-    public get FilterModels() {
-        return this.BarFilterModels;
-    }
-    @action
-    public AddFilterModels(filterModels: FilterModel[]): void {
-        filterModels.filter(f => f !== null).forEach(fm => this.BarFilterModels.push(fm));
-    }
-    @action
-    public RemoveFilterModels(filterModels: FilterModel[]): void {
-        ArrayUtil.RemoveMany(this.BarFilterModels, filterModels);
-    }
-
-    @computed
-    public get FilterString(): string {
-        if (this.OverridingFilters.length > 0) {
-            return "(" + this.OverridingFilters.filter(fm => fm !== null).map(fm => fm.ToPythonString()).join(" || ") + ")";
-        }
-        let filterModels: FilterModel[] = [];
-        return FilterModel.GetFilterModelsRecursive(this, new Set<IBaseFilterProvider>(), filterModels, true);
-    }
-
-    public get BrushString(): string[] {
-        let brushes: string[] = [];
-        this.BrushLinks.map(brushLink => {
-            let brushHistogram = Cast(brushLink.b.data, HistogramField);
-            if (brushHistogram) {
-                let filterModels: FilterModel[] = [];
-                brushes.push(FilterModel.GetFilterModelsRecursive(brushHistogram.HistoOp, new Set<IBaseFilterProvider>(), filterModels, false));
-            }
-        });
-        return brushes;
-    }
-
-    _stackedFilters: (FilterModel[])[] = [];
-    @action
-    public DrillDown(up: boolean) {
-        if (!up) {
-            if (!this.BarFilterModels.length) {
-                return;
-            }
-            this._stackedFilters.push(this.BarFilterModels.map(f => f));
-            this.OverridingFilters.length = 0;
-            this.OverridingFilters.push(...this._stackedFilters[this._stackedFilters.length - 1]);
-            this.BarFilterModels.map(fm => fm).map(fm => this.RemoveFilterModels([fm]));
-            //this.updateHistogram();
-        } else {
-            this.OverridingFilters.length = 0;
-            if (this._stackedFilters.length) {
-                this.OverridingFilters.push(...this._stackedFilters.pop()!);
-            }
-            // else 
-            //     this.updateHistogram();
-        }
-    }
-
-    private getAggregateParameters(histoX: AttributeTransformationModel, histoY: AttributeTransformationModel, histoValue: AttributeTransformationModel) {
-        let allAttributes = new Array<AttributeTransformationModel>(histoX, histoY, histoValue);
-        allAttributes = ArrayUtil.Distinct(allAttributes.filter(a => a.AggregateFunction !== AggregateFunction.None));
-
-        let numericDataTypes = [DataType.Int, DataType.Double, DataType.Float];
-        let perBinAggregateParameters: AggregateParameters[] = ModelHelpers.GetAggregateParametersWithMargins(this.Schema!.distinctAttributeParameters, allAttributes);
-        let globalAggregateParameters: AggregateParameters[] = [];
-        [histoX, histoY]
-            .filter(a => a.AggregateFunction === AggregateFunction.None && ArrayUtil.Contains(numericDataTypes, a.AttributeModel.DataType))
-            .forEach(a => {
-                let avg = new AverageAggregateParameters();
-                avg.attributeParameters = ModelHelpers.GetAttributeParameters(a.AttributeModel);
-                globalAggregateParameters.push(avg);
-            });
-        return [perBinAggregateParameters, globalAggregateParameters];
-    }
-
-    public CreateOperationParameters(): HistogramOperationParameters | undefined {
-        if (this.X && this.Y && this.V) {
-            let [perBinAggregateParameters, globalAggregateParameters] = this.getAggregateParameters(this.X, this.Y, this.V);
-            return new HistogramOperationParameters({
-                enableBrushComputation: true,
-                adapterName: this.SchemaName,
-                filter: this.FilterString,
-                brushes: this.BrushString,
-                binningParameters: [ModelHelpers.GetBinningParameters(this.X, SETTINGS_X_BINS, this.QRange ? this.QRange.minValue : undefined, this.QRange ? this.QRange.maxValue : undefined),
-                ModelHelpers.GetBinningParameters(this.Y, SETTINGS_Y_BINS)],
-                sampleStreamBlockSize: SETTINGS_SAMPLE_SIZE,
-                perBinAggregateParameters: perBinAggregateParameters,
-                globalAggregateParameters: globalAggregateParameters,
-                sortPerBinAggregateParameter: undefined,
-                attributeCalculatedParameters: CalculatedAttributeManager
-                    .AllCalculatedAttributes.map(a => ModelHelpers.GetAttributeParametersFromAttributeModel(a)),
-                degreeOfParallism: 1, // Settings.Instance.DegreeOfParallelism,
-                isCachable: false
-            });
-        }
-    }
-
-    @action
-    public async Update(): Promise<void> {
-        this.BrushColors = this.BrushLinks.map(e => NumCast(e.l.backgroundColor));
-        return super.Update();
-    }
-}
-
-
diff --git a/src/client/northstar/utils/ArrayUtil.ts b/src/client/northstar/utils/ArrayUtil.ts
deleted file mode 100644
index 12b8d8e77..000000000
--- a/src/client/northstar/utils/ArrayUtil.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-import { Exception } from "../model/idea/idea";
-
-export class ArrayUtil {
-
-    public static Contains(arr1: any[], arr2: any): boolean {
-        if (arr1.length === 0) {
-            return false;
-        }
-        let isComplex = typeof arr1[0] === "object";
-        for (const ele of arr1) {
-            if (isComplex && "Equals" in ele) {
-                if (ele.Equals(arr2)) {
-                    return true;
-                }
-            }
-            else {
-                if (ele === arr2) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-
-    public static RemoveMany(arr: any[], elements: Object[]) {
-        elements.forEach(e => ArrayUtil.Remove(arr, e));
-    }
-
-    public static AddMany(arr: any[], others: Object[]) {
-        arr.push(...others);
-    }
-
-    public static Clear(arr: any[]) {
-        arr.splice(0, arr.length);
-    }
-
-
-    public static Remove(arr: any[], other: Object) {
-        const index = ArrayUtil.IndexOfWithEqual(arr, other);
-        if (index === -1) {
-            return;
-        }
-        arr.splice(index, 1);
-    }
-
-
-    public static First<T>(arr: T[], predicate: (x: any) => boolean): T {
-        let filtered = arr.filter(predicate);
-        if (filtered.length > 0) {
-            return filtered[0];
-        }
-        throw new Exception();
-    }
-
-    public static FirstOrDefault<T>(arr: T[], predicate: (x: any) => boolean): T | undefined {
-        let filtered = arr.filter(predicate);
-        if (filtered.length > 0) {
-            return filtered[0];
-        }
-        return undefined;
-    }
-
-    public static Distinct(arr: any[]): any[] {
-        let ret = [];
-        for (const ele of arr) {
-            if (!ArrayUtil.Contains(ret, ele)) {
-                ret.push(ele);
-            }
-        }
-        return ret;
-    }
-
-    public static IndexOfWithEqual(arr: any[], other: any): number {
-        for (let i = 0; i < arr.length; i++) {
-            let isComplex = typeof arr[0] === "object";
-            if (isComplex && "Equals" in arr[i]) {
-                if (arr[i].Equals(other)) {
-                    return i;
-                }
-            }
-            else {
-                if (arr[i] === other) {
-                    return i;
-                }
-            }
-        }
-        return -1;
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/utils/Extensions.ts b/src/client/northstar/utils/Extensions.ts
deleted file mode 100644
index df14d4da0..000000000
--- a/src/client/northstar/utils/Extensions.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-interface String {
-    ReplaceAll(toReplace: string, replacement: string): string;
-    Truncate(length: number, replacement: string): String;
-}
-
-String.prototype.ReplaceAll = function (toReplace: string, replacement: string): string {
-    var target = this;
-    return target.split(toReplace).join(replacement);
-};
-
-String.prototype.Truncate = function (length: number, replacement: string): String {
-    var target = this;
-    if (target.length >= length) {
-        target = target.slice(0, Math.max(0, length - replacement.length)) + replacement;
-    }
-    return target;
-};
-
-interface Math {
-    log10(val: number): number;
-}
-
-Math.log10 = function (val: number): number {
-    return Math.log(val) / Math.LN10;
-};
-
-declare interface ObjectConstructor {
-    assign(...objects: Object[]): Object;
-}
diff --git a/src/client/northstar/utils/GeometryUtil.ts b/src/client/northstar/utils/GeometryUtil.ts
deleted file mode 100644
index d5220c479..000000000
--- a/src/client/northstar/utils/GeometryUtil.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-import { MathUtil, PIXIRectangle, PIXIPoint } from "./MathUtil";
-
-
-export class GeometryUtil {
-
-    public static ComputeBoundingBox(points: { x: number, y: number }[], scale = 1, padding: number = 0): PIXIRectangle {
-        let minX: number = Number.MAX_VALUE;
-        let minY: number = Number.MAX_VALUE;
-        let maxX: number = Number.MIN_VALUE;
-        let maxY: number = Number.MIN_VALUE;
-        for (const point of points) {
-            if (point.x < minX) {
-                minX = point.x;
-            }
-            if (point.y < minY) {
-                minY = point.y;
-            }
-            if (point.x > maxX) {
-                maxX = point.x;
-            }
-            if (point.y > maxY) {
-                maxY = point.y;
-            }
-        }
-        return new PIXIRectangle(minX * scale - padding, minY * scale - padding, (maxX - minX) * scale + padding * 2, (maxY - minY) * scale + padding * 2);
-    }
-
-    public static RectangleOverlap(rect1: PIXIRectangle, rect2: PIXIRectangle) {
-        let x_overlap = Math.max(0, Math.min(rect1.right, rect2.right) - Math.max(rect1.left, rect2.left));
-        let y_overlap = Math.max(0, Math.min(rect1.bottom, rect2.bottom) - Math.max(rect1.top, rect2.top));
-        return x_overlap * y_overlap;
-    }
-
-    public static RotatePoints(center: { x: number, y: number }, points: { x: number, y: number }[], angle: number): PIXIPoint[] {
-        const rotate = (cx: number, cy: number, x: number, y: number, angle: number) => {
-            const radians = angle,
-                cos = Math.cos(radians),
-                sin = Math.sin(radians),
-                nx = (cos * (x - cx)) + (sin * (y - cy)) + cx,
-                ny = (cos * (y - cy)) - (sin * (x - cx)) + cy;
-            return new PIXIPoint(nx, ny);
-        };
-        return points.map(p => rotate(center.x, center.y, p.x, p.y, angle));
-    }
-
-    public static LineByLeastSquares(points: { x: number, y: number }[]): PIXIPoint[] {
-        let sum_x: number = 0;
-        let sum_y: number = 0;
-        let sum_xy: number = 0;
-        let sum_xx: number = 0;
-        let count: number = 0;
-
-        let x: number = 0;
-        let y: number = 0;
-
-
-        if (points.length === 0) {
-            return [];
-        }
-
-        for (const point of points) {
-            x = point.x;
-            y = point.y;
-            sum_x += x;
-            sum_y += y;
-            sum_xx += x * x;
-            sum_xy += x * y;
-            count++;
-        }
-
-        let m = (count * sum_xy - sum_x * sum_y) / (count * sum_xx - sum_x * sum_x);
-        let b = (sum_y / count) - (m * sum_x) / count;
-        let result: PIXIPoint[] = new Array<PIXIPoint>();
-
-        for (const point of points) {
-            x = point.x;
-            y = x * m + b;
-            result.push(new PIXIPoint(x, y));
-        }
-        return result;
-    }
-
-    // public static PointInsidePolygon(vs:Point[], x:number, y:number):boolean {
-    //     // ray-casting algorithm based on
-    //     // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
-
-    //     var inside = false;
-    //     for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
-    //         var xi = vs[i].x, yi = vs[i].y;
-    //         var xj = vs[j].x, yj = vs[j].y;
-
-    //         var intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
-    //         if (intersect) 
-    //            inside = !inside;
-    //     }
-
-    //     return inside;
-    // };
-
-    public static IntersectLines(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number): boolean {
-        let a1: number, a2: number, b1: number, b2: number, c1: number, c2: number;
-        let r1: number, r2: number, r3: number, r4: number;
-        let denom: number, offset: number, num: number;
-
-        a1 = y2 - y1;
-        b1 = x1 - x2;
-        c1 = (x2 * y1) - (x1 * y2);
-        r3 = ((a1 * x3) + (b1 * y3) + c1);
-        r4 = ((a1 * x4) + (b1 * y4) + c1);
-
-        if ((r3 !== 0) && (r4 !== 0) && (MathUtil.Sign(r3) === MathUtil.Sign(r4))) {
-            return false;
-        }
-
-        a2 = y4 - y3;
-        b2 = x3 - x4;
-        c2 = (x4 * y3) - (x3 * y4);
-
-        r1 = (a2 * x1) + (b2 * y1) + c2;
-        r2 = (a2 * x2) + (b2 * y2) + c2;
-
-        if ((r1 !== 0) && (r2 !== 0) && (MathUtil.Sign(r1) === MathUtil.Sign(r2))) {
-            return false;
-        }
-
-        denom = (a1 * b2) - (a2 * b1);
-
-        if (denom === 0) {
-            return false;
-        }
-        return true;
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/utils/IDisposable.ts b/src/client/northstar/utils/IDisposable.ts
deleted file mode 100644
index 5e9843326..000000000
--- a/src/client/northstar/utils/IDisposable.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export interface IDisposable {
-    Dispose(): void;
-}
\ No newline at end of file
diff --git a/src/client/northstar/utils/IEquatable.ts b/src/client/northstar/utils/IEquatable.ts
deleted file mode 100644
index 2f81c2478..000000000
--- a/src/client/northstar/utils/IEquatable.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export interface IEquatable {
-    Equals(other: Object): boolean;
-}
\ No newline at end of file
diff --git a/src/client/northstar/utils/KeyCodes.ts b/src/client/northstar/utils/KeyCodes.ts
deleted file mode 100644
index 044569ffe..000000000
--- a/src/client/northstar/utils/KeyCodes.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * Class contains the keycodes for keys on your keyboard.
- *
- * Useful for auto completion:
- *
- * ```
- * switch (event.key)
- * {
- *      case KeyCode.UP:
- *      {
- *      	// Up key pressed
- *       	break;
- *      }
- *      case KeyCode.DOWN:
- *      {
- *      	// Down key pressed
- *       	break;
- *      }
- *      case KeyCode.LEFT:
- *      {
- *      	// Left key pressed
- *       	break;
- *      }
- *      case KeyCode.RIGHT:
- *      {
- *      	// Right key pressed
- *       	break;
- *      }
- *      default:
- *      {
- *      	// ignore
- *      	break;
- *      }
- * }
- * ```
- */
-export class KeyCodes
-{
-	public static TAB:number = 9;
-	public static CAPS_LOCK:number = 20;
-	public static SHIFT:number = 16;
-	public static CONTROL:number = 17;
-	public static SPACE:number = 32;
-	public static DOWN:number = 40;
-	public static UP:number = 38;
-	public static LEFT:number = 37;
-	public static RIGHT:number = 39;
-	public static ESCAPE:number = 27;
-	public static F1:number = 112;
-	public static F2:number = 113;
-	public static F3:number = 114;
-	public static F4:number = 115;
-	public static F5:number = 116;
-	public static F6:number = 117;
-	public static F7:number = 118;
-	public static F8:number = 119;
-	public static F9:number = 120;
-	public static F10:number = 121;
-	public static F11:number = 122;
-	public static F12:number = 123;
-	public static INSERT:number = 45;
-	public static HOME:number = 36;
-	public static PAGE_UP:number = 33;
-	public static PAGE_DOWN:number = 34;
-	public static DELETE:number = 46;
-	public static END:number = 35;
-	public static ENTER:number = 13;
-	public static BACKSPACE:number = 8;
-	public static NUMPAD_0:number = 96;
-	public static NUMPAD_1:number = 97;
-	public static NUMPAD_2:number = 98;
-	public static NUMPAD_3:number = 99;
-	public static NUMPAD_4:number = 100;
-	public static NUMPAD_5:number = 101;
-	public static NUMPAD_6:number = 102;
-	public static NUMPAD_7:number = 103;
-	public static NUMPAD_8:number = 104;
-	public static NUMPAD_9:number = 105;
-	public static NUMPAD_DIVIDE:number = 111;
-	public static NUMPAD_ADD:number = 107;
-	public static NUMPAD_ENTER:number = 13;
-	public static NUMPAD_DECIMAL:number = 110;
-	public static NUMPAD_SUBTRACT:number = 109;
-	public static NUMPAD_MULTIPLY:number = 106;
-	public static SEMICOLON:number = 186;
-	public static EQUAL:number = 187;
-	public static COMMA:number = 188;
-	public static MINUS:number = 189;
-	public static PERIOD:number = 190;
-	public static SLASH:number = 191;
-	public static BACKQUOTE:number = 192;
-	public static LEFTBRACKET:number = 219;
-	public static BACKSLASH:number = 220;
-	public static RIGHTBRACKET:number = 221;
-	public static QUOTE:number = 222;
-	public static ALT:number = 18;
-	public static COMMAND:number = 15;
-	public static NUMPAD:number = 21;
-	public static A:number = 65;
-	public static B:number = 66;
-	public static C:number = 67;
-	public static D:number = 68;
-	public static E:number = 69;
-	public static F:number = 70;
-	public static G:number = 71;
-	public static H:number = 72;
-	public static I:number = 73;
-	public static J:number = 74;
-	public static K:number = 75;
-	public static L:number = 76;
-	public static M:number = 77;
-	public static N:number = 78;
-	public static O:number = 79;
-	public static P:number = 80;
-	public static Q:number = 81;
-	public static R:number = 82;
-	public static S:number = 83;
-	public static T:number = 84;
-	public static U:number = 85;
-	public static V:number = 86;
-	public static W:number = 87;
-	public static X:number = 88;
-	public static Y:number = 89;
-	public static Z:number = 90;
-	public static NUM_0:number = 48;
-	public static NUM_1:number = 49;
-	public static NUM_2:number = 50;
-	public static NUM_3:number = 51;
-	public static NUM_4:number = 52;
-	public static NUM_5:number = 53;
-	public static NUM_6:number = 54;
-	public static NUM_7:number = 55;
-	public static NUM_8:number = 56;
-	public static NUM_9:number = 57;
-	public static SUBSTRACT:number = 189;
-	public static ADD:number = 187;
-}
\ No newline at end of file
diff --git a/src/client/northstar/utils/LABColor.ts b/src/client/northstar/utils/LABColor.ts
deleted file mode 100644
index 72e46fb7f..000000000
--- a/src/client/northstar/utils/LABColor.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-
-export class LABColor {
-    public L: number;
-    public A: number;
-    public B: number;
-
-    // constructor - takes three floats for lightness and color-opponent dimensions
-    constructor(l: number, a: number, b: number) {
-        this.L = l;
-        this.A = a;
-        this.B = b;
-    }
-
-    // static function for linear interpolation between two LABColors
-    public static Lerp(a: LABColor, b: LABColor, t: number): LABColor {
-        return new LABColor(LABColor.LerpNumber(a.L, b.L, t), LABColor.LerpNumber(a.A, b.A, t), LABColor.LerpNumber(a.B, b.B, t));
-    }
-
-    public static LerpNumber(a: number, b: number, percent: number): number {
-        return a + percent * (b - a);
-    }
-
-    static hexToRGB(hex: number, alpha: number): number[] {
-        var r = (hex & (0xff << 16)) >> 16;
-        var g = (hex & (0xff << 8)) >> 8;
-        var b = (hex & (0xff << 0)) >> 0;
-        return [r, g, b];
-    }
-    static RGBtoHex(red: number, green: number, blue: number): number {
-        return blue | (green << 8) | (red << 16);
-    }
-
-    public static RGBtoHexString(rgb: number): string {
-        let str = "#" + this.hex((rgb & (0xff << 16)) >> 16) + this.hex((rgb & (0xff << 8)) >> 8) + this.hex((rgb & (0xff << 0)) >> 0);
-        return str;
-    }
-
-    static hex(x: number): string {
-        var hexDigits = new Array
-            ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f");
-        return isNaN(x) ? "00" : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16];
-    }
-
-    public static FromColor(c: number): LABColor {
-        var rgb = LABColor.hexToRGB(c, 0);
-        var r = LABColor.d3_rgb_xyz(rgb[0] * 255);
-        var g = LABColor.d3_rgb_xyz(rgb[1] * 255);
-        var b = LABColor.d3_rgb_xyz(rgb[2] * 255);
-
-        var x = LABColor.d3_xyz_lab((0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / LABColor.d3_lab_X);
-        var y = LABColor.d3_xyz_lab((0.2126729 * r + 0.7151522 * g + 0.0721750 * b) / LABColor.d3_lab_Y);
-        var z = LABColor.d3_xyz_lab((0.0193339 * r + 0.1191920 * g + 0.9503041 * b) / LABColor.d3_lab_Z);
-        var lab = new LABColor(116 * y - 16, 500 * (x - y), 200 * (y - z));
-        return lab;
-    }
-
-    private static d3_lab_X: number = 0.950470;
-    private static d3_lab_Y: number = 1;
-    private static d3_lab_Z: number = 1.088830;
-
-    public static d3_lab_xyz(x: number): number {
-        return x > 0.206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
-    }
-
-    public static d3_xyz_rgb(r: number): number {
-        return Math.round(255 * (r <= 0.00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - 0.055));
-    }
-
-    public static d3_rgb_xyz(r: number): number {
-        return (r /= 255) <= 0.04045 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
-    }
-
-    public static d3_xyz_lab(x: number): number {
-        return x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
-    }
-
-    public static ToColor(lab: LABColor): number {
-        var y = (lab.L + 16) / 116;
-        var x = y + lab.A / 500;
-        var z = y - lab.B / 200;
-        x = LABColor.d3_lab_xyz(x) * LABColor.d3_lab_X;
-        y = LABColor.d3_lab_xyz(y) * LABColor.d3_lab_Y;
-        z = LABColor.d3_lab_xyz(z) * LABColor.d3_lab_Z;
-
-        return LABColor.RGBtoHex(
-            LABColor.d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - 0.4985314 * z) / 255,
-            LABColor.d3_xyz_rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z) / 255,
-            LABColor.d3_xyz_rgb(0.0556434 * x - 0.2040259 * y + 1.0572252 * z) / 255);
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/utils/MathUtil.ts b/src/client/northstar/utils/MathUtil.ts
deleted file mode 100644
index 5def5e704..000000000
--- a/src/client/northstar/utils/MathUtil.ts
+++ /dev/null
@@ -1,249 +0,0 @@
-
-
-export class PIXIPoint {
-    public get x() { return this.coords[0]; }
-    public get y() { return this.coords[1]; }
-    public set x(value: number) { this.coords[0] = value; }
-    public set y(value: number) { this.coords[1] = value; }
-    public coords: number[] = [0, 0];
-    constructor(x: number, y: number) {
-        this.coords[0] = x;
-        this.coords[1] = y;
-    }
-}
-
-export class PIXIRectangle {
-    public x: number;
-    public y: number;
-    public width: number;
-    public height: number;
-    public get left() { return this.x; }
-    public get right() { return this.x + this.width; }
-    public get top() { return this.y; }
-    public get bottom() { return this.top + this.height; }
-    public static get EMPTY() { return new PIXIRectangle(0, 0, -1, -1); }
-    constructor(x: number, y: number, width: number, height: number) {
-        this.x = x;
-        this.y = y;
-        this.width = width;
-        this.height = height;
-    }
-}
-
-export class MathUtil {
-
-    public static EPSILON: number = 0.001;
-
-    public static Sign(value: number): number {
-        return value >= 0 ? 1 : -1;
-    }
-
-    public static AddPoint(p1: PIXIPoint, p2: PIXIPoint, inline: boolean = false): PIXIPoint {
-        if (inline) {
-            p1.x += p2.x;
-            p1.y += p2.y;
-            return p1;
-        }
-        else {
-            return new PIXIPoint(p1.x + p2.x, p1.y + p2.y);
-        }
-    }
-
-    public static Perp(p1: PIXIPoint): PIXIPoint {
-        return new PIXIPoint(-p1.y, p1.x);
-    }
-
-    public static DividePoint(p1: PIXIPoint, by: number, inline: boolean = false): PIXIPoint {
-        if (inline) {
-            p1.x /= by;
-            p1.y /= by;
-            return p1;
-        }
-        else {
-            return new PIXIPoint(p1.x / by, p1.y / by);
-        }
-    }
-
-    public static MultiplyConstant(p1: PIXIPoint, by: number, inline: boolean = false) {
-        if (inline) {
-            p1.x *= by;
-            p1.y *= by;
-            return p1;
-        }
-        else {
-            return new PIXIPoint(p1.x * by, p1.y * by);
-        }
-    }
-
-    public static SubtractPoint(p1: PIXIPoint, p2: PIXIPoint, inline: boolean = false): PIXIPoint {
-        if (inline) {
-            p1.x -= p2.x;
-            p1.y -= p2.y;
-            return p1;
-        }
-        else {
-            return new PIXIPoint(p1.x - p2.x, p1.y - p2.y);
-        }
-    }
-
-    public static Area(rect: PIXIRectangle): number {
-        return rect.width * rect.height;
-    }
-
-    public static DistToLineSegment(v: PIXIPoint, w: PIXIPoint, p: PIXIPoint) {
-        // Return minimum distance between line segment vw and point p
-        const l2 = MathUtil.DistSquared(v, w);  // i.e. |w-v|^2 -  avoid a sqrt
-        if (l2 === 0.0) return MathUtil.Dist(p, v);   // v === w case
-        // Consider the line extending the segment, parameterized as v + t (w - v).
-        // We find projection of point p onto the line. 
-        // It falls where t = [(p-v) . (w-v)] / |w-v|^2
-        // We clamp t from [0,1] to handle points outside the segment vw.
-        const dot = MathUtil.Dot(
-            MathUtil.SubtractPoint(p, v),
-            MathUtil.SubtractPoint(w, v)) / l2;
-        const t = Math.max(0, Math.min(1, dot));
-        // Projection falls on the segment
-        const projection = MathUtil.AddPoint(v,
-            MathUtil.MultiplyConstant(
-                MathUtil.SubtractPoint(w, v), t));
-        return MathUtil.Dist(p, projection);
-    }
-
-    public static LineSegmentIntersection(ps1: PIXIPoint, pe1: PIXIPoint, ps2: PIXIPoint, pe2: PIXIPoint): PIXIPoint | undefined {
-        const a1 = pe1.y - ps1.y;
-        const b1 = ps1.x - pe1.x;
-
-        const a2 = pe2.y - ps2.y;
-        const b2 = ps2.x - pe2.x;
-
-        const delta = a1 * b2 - a2 * b1;
-        if (delta === 0) {
-            return undefined;
-        }
-        const c2 = a2 * ps2.x + b2 * ps2.y;
-        const c1 = a1 * ps1.x + b1 * ps1.y;
-        const invdelta = 1 / delta;
-        return new PIXIPoint((b2 * c1 - b1 * c2) * invdelta, (a1 * c2 - a2 * c1) * invdelta);
-    }
-
-    public static PointInPIXIRectangle(p: PIXIPoint, rect: PIXIRectangle): boolean {
-        if (p.x < rect.left - this.EPSILON) {
-            return false;
-        }
-        if (p.x > rect.right + this.EPSILON) {
-            return false;
-        }
-        if (p.y < rect.top - this.EPSILON) {
-            return false;
-        }
-        if (p.y > rect.bottom + this.EPSILON) {
-            return false;
-        }
-
-        return true;
-    }
-
-    public static LinePIXIRectangleIntersection(lineFrom: PIXIPoint, lineTo: PIXIPoint, rect: PIXIRectangle): Array<PIXIPoint> {
-        const r1 = new PIXIPoint(rect.left, rect.top);
-        const r2 = new PIXIPoint(rect.right, rect.top);
-        const r3 = new PIXIPoint(rect.right, rect.bottom);
-        const r4 = new PIXIPoint(rect.left, rect.bottom);
-        const ret = new Array<PIXIPoint>();
-        const dist = this.Dist(lineFrom, lineTo);
-        let inter = this.LineSegmentIntersection(lineFrom, lineTo, r1, r2);
-        if (inter && this.PointInPIXIRectangle(inter, rect) &&
-            this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) {
-            ret.push(inter);
-        }
-        inter = this.LineSegmentIntersection(lineFrom, lineTo, r2, r3);
-        if (inter && this.PointInPIXIRectangle(inter, rect) &&
-            this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) {
-            ret.push(inter);
-        }
-        inter = this.LineSegmentIntersection(lineFrom, lineTo, r3, r4);
-        if (inter && this.PointInPIXIRectangle(inter, rect) &&
-            this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) {
-            ret.push(inter);
-        }
-        inter = this.LineSegmentIntersection(lineFrom, lineTo, r4, r1);
-        if (inter && this.PointInPIXIRectangle(inter, rect) &&
-            this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) {
-            ret.push(inter);
-        }
-        return ret;
-    }
-
-    public static Intersection(rect1: PIXIRectangle, rect2: PIXIRectangle): PIXIRectangle {
-        const left = Math.max(rect1.x, rect2.x);
-        const right = Math.min(rect1.x + rect1.width, rect2.x + rect2.width);
-        const top = Math.max(rect1.y, rect2.y);
-        const bottom = Math.min(rect1.y + rect1.height, rect2.y + rect2.height);
-        return new PIXIRectangle(left, top, right - left, bottom - top);
-    }
-
-    public static Dist(p1: PIXIPoint, p2: PIXIPoint): number {
-        return Math.sqrt(MathUtil.DistSquared(p1, p2));
-    }
-
-    public static Dot(p1: PIXIPoint, p2: PIXIPoint): number {
-        return p1.x * p2.x + p1.y * p2.y;
-    }
-
-    public static Normalize(p1: PIXIPoint) {
-        const d = this.Length(p1);
-        return new PIXIPoint(p1.x / d, p1.y / d);
-    }
-
-    public static Length(p1: PIXIPoint): number {
-        return Math.sqrt(p1.x * p1.x + p1.y * p1.y);
-    }
-
-    public static DistSquared(p1: PIXIPoint, p2: PIXIPoint): number {
-        const a = p1.x - p2.x;
-        const b = p1.y - p2.y;
-        return (a * a + b * b);
-    }
-
-    public static RectIntersectsRect(r1: PIXIRectangle, r2: PIXIRectangle): boolean {
-        return !(r2.x > r1.x + r1.width ||
-            r2.x + r2.width < r1.x ||
-            r2.y > r1.y + r1.height ||
-            r2.y + r2.height < r1.y);
-    }
-
-    public static ArgMin(temp: number[]): number {
-        let index = 0;
-        let value = temp[0];
-        for (let i = 1; i < temp.length; i++) {
-            if (temp[i] < value) {
-                value = temp[i];
-                index = i;
-            }
-        }
-        return index;
-    }
-
-    public static ArgMax(temp: number[]): number {
-        let index = 0;
-        let value = temp[0];
-        for (let i = 1; i < temp.length; i++) {
-            if (temp[i] > value) {
-                value = temp[i];
-                index = i;
-            }
-        }
-        return index;
-    }
-
-    public static Combinations<T>(chars: T[]) {
-        const result = new Array<T>();
-        const f = (prefix: any, chars: any) => {
-            for (let i = 0; i < chars.length; i++) {
-                result.push(prefix.concat(chars[i]));
-                f(prefix.concat(chars[i]), chars.slice(i + 1));
-            }
-        };
-        f([], chars);
-        return result;
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/utils/PartialClass.ts b/src/client/northstar/utils/PartialClass.ts
deleted file mode 100644
index 2f20de96f..000000000
--- a/src/client/northstar/utils/PartialClass.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-
-export class PartialClass<T> {
-
-    constructor(data?: Partial<T>) {
-        Object.assign(this, data);
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/utils/SizeConverter.ts b/src/client/northstar/utils/SizeConverter.ts
deleted file mode 100644
index a52890ed9..000000000
--- a/src/client/northstar/utils/SizeConverter.ts
+++ /dev/null
@@ -1,101 +0,0 @@
-import { PIXIPoint } from "./MathUtil";
-import { VisualBinRange } from "../model/binRanges/VisualBinRange";
-import { Bin, DoubleValueAggregateResult, AggregateKey } from "../model/idea/idea";
-import { ModelHelpers } from "../model/ModelHelpers";
-import { observable, action, computed } from "mobx";
-
-export class SizeConverter {
-    public DataMins: Array<number> = new Array<number>(2);
-    public DataMaxs: Array<number> = new Array<number>(2);
-    public DataRanges: Array<number> = new Array<number>(2);
-    public MaxLabelSizes: Array<PIXIPoint> = new Array<PIXIPoint>(2);
-    public RenderDimension: number = 300;
-
-    @observable _leftOffset: number = 40;
-    @observable _rightOffset: number = 20;
-    @observable _topOffset: number = 20;
-    @observable _bottomOffset: number = 45;
-    @observable _labelAngle: number = 0;
-    @observable _isSmall: boolean = false;
-    @observable public Initialized = 0;
-
-    @action public SetIsSmall(isSmall: boolean) { this._isSmall = isSmall; }
-    @action public SetLabelAngle(angle: number) { this._labelAngle = angle; }
-    @computed public get IsSmall() { return this._isSmall; }
-    @computed public get LabelAngle() { return this._labelAngle; }
-    @computed public get LeftOffset() { return this.IsSmall ? 5 : this._leftOffset; }
-    @computed public get RightOffset() { return this.IsSmall ? 5 : !this._labelAngle ? this._bottomOffset : Math.max(this._rightOffset, Math.cos(this._labelAngle) * (this.MaxLabelSizes[0].x + 18)); }
-    @computed public get TopOffset() { return this.IsSmall ? 5 : this._topOffset; }
-    @computed public get BottomOffset() { return this.IsSmall ? 25 : !this._labelAngle ? this._bottomOffset : Math.max(this._bottomOffset, Math.sin(this._labelAngle) * (this.MaxLabelSizes[0].x + 18)) + 18; }
-
-    public SetVisualBinRanges(visualBinRanges: Array<VisualBinRange>) {
-        this.Initialized++;
-        var xLabels = visualBinRanges[0].GetLabels();
-        var yLabels = visualBinRanges[1].GetLabels();
-        var xLabelStrings = xLabels.map(l => l.label!).sort(function (a, b) { return b.length - a.length; });
-        var yLabelStrings = yLabels.map(l => l.label!).sort(function (a, b) { return b.length - a.length; });
-
-        var metricsX = { width: 75 }; // RenderUtils.MeasureText(FontStyles.Default.fontFamily.toString(), 12, // FontStyles.AxisLabel.fontSize as number,
-        //xLabelStrings[0]!.slice(0, 20)) // StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS));
-        var metricsY = { width: 22 }; // RenderUtils.MeasureText(FontStyles.Default.fontFamily.toString(), 12, // FontStyles.AxisLabel.fontSize as number,
-        // yLabelStrings[0]!.slice(0, 20)); // StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS));
-        this.MaxLabelSizes[0] = new PIXIPoint(metricsX.width, 12);// FontStyles.AxisLabel.fontSize as number);
-        this.MaxLabelSizes[1] = new PIXIPoint(metricsY.width, 12); // FontStyles.AxisLabel.fontSize as number);
-
-        this._leftOffset = Math.max(10, metricsY.width + 10 + 20);
-
-        this.DataMins[0] = xLabels.map(l => l.minValue!).reduce((m, c) => Math.min(m, c), Number.MAX_VALUE);
-        this.DataMins[1] = yLabels.map(l => l.minValue!).reduce((m, c) => Math.min(m, c), Number.MAX_VALUE);
-        this.DataMaxs[0] = xLabels.map(l => l.maxValue!).reduce((m, c) => Math.max(m, c), Number.MIN_VALUE);
-        this.DataMaxs[1] = yLabels.map(l => l.maxValue!).reduce((m, c) => Math.max(m, c), Number.MIN_VALUE);
-
-        this.DataRanges[0] = this.DataMaxs[0] - this.DataMins[0];
-        this.DataRanges[1] = this.DataMaxs[1] - this.DataMins[1];
-    }
-
-    public DataToScreenNormalizedRange(dataValue: number, normalization: number, axis: number, binBrushMaxAxis: number) {
-        var value = normalization !== 1 - axis || binBrushMaxAxis === 0 ? dataValue : (dataValue - 0) / (binBrushMaxAxis - 0) * this.DataRanges[axis];
-        var from = this.DataToScreenCoord(Math.min(0, value), axis);
-        var to = this.DataToScreenCoord(Math.max(0, value), axis);
-        return [from, value, to];
-    }
-
-    public DataToScreenPointRange(axis: number, bin: Bin, aggregateKey: AggregateKey) {
-        var value = ModelHelpers.GetAggregateResult(bin, aggregateKey) as DoubleValueAggregateResult;
-        if (value && value.hasResult) {
-            return [this.DataToScreenCoord(value.result!, axis) - 5,
-            this.DataToScreenCoord(value.result!, axis) + 5];
-        }
-        return [undefined, undefined];
-    }
-
-    public DataToScreenXAxisRange(visualBinRanges: VisualBinRange[], index: number, bin: Bin) {
-        var value = visualBinRanges[0].GetValueFromIndex(bin.binIndex!.indices![index]);
-        return [this.DataToScreenX(value), this.DataToScreenX(visualBinRanges[index].AddStep(value))];
-    }
-    public DataToScreenYAxisRange(visualBinRanges: VisualBinRange[], index: number, bin: Bin) {
-        var value = visualBinRanges[1].GetValueFromIndex(bin.binIndex!.indices![index]);
-        return [this.DataToScreenY(value), this.DataToScreenY(visualBinRanges[index].AddStep(value))];
-    }
-
-    public DataToScreenX(x: number): number {
-        return ((x - this.DataMins[0]) / this.DataRanges[0]) * this.RenderDimension;
-    }
-    public DataToScreenY(y: number, flip: boolean = true) {
-        var retY = ((y - this.DataMins[1]) / this.DataRanges[1]) * this.RenderDimension;
-        return flip ? (this.RenderDimension) - retY : retY;
-    }
-    public DataToScreenCoord(v: number, axis: number) {
-        if (axis === 0) {
-            return this.DataToScreenX(v);
-        }
-        return this.DataToScreenY(v);
-    }
-    public DataToScreenRange(minVal: number, maxVal: number, axis: number) {
-        let xFrom = this.DataToScreenX(axis === 0 ? minVal : this.DataMins[0]);
-        let xTo = this.DataToScreenX(axis === 0 ? maxVal : this.DataMaxs[0]);
-        let yFrom = this.DataToScreenY(axis === 1 ? minVal : this.DataMins[1]);
-        let yTo = this.DataToScreenY(axis === 1 ? maxVal : this.DataMaxs[1]);
-        return { xFrom, yFrom, xTo, yTo };
-    }
-}
\ No newline at end of file
diff --git a/src/client/northstar/utils/StyleContants.ts b/src/client/northstar/utils/StyleContants.ts
deleted file mode 100644
index e9b6e0297..000000000
--- a/src/client/northstar/utils/StyleContants.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-import { PIXIPoint } from "./MathUtil";
-
-export class StyleConstants {
-
-    static DEFAULT_FONT: string = "Roboto Condensed";
-
-    static MENU_SUBMENU_WIDTH: number = 85;
-    static MENU_SUBMENU_HEIGHT: number = 400;
-    static MENU_BOX_SIZE: PIXIPoint = new PIXIPoint(80, 35);
-    static MENU_BOX_PADDING: number = 10;
-
-    static OPERATOR_MENU_LARGE: number = 35;
-    static OPERATOR_MENU_SMALL: number = 25;
-    static BRUSH_PALETTE: number[] = [0x42b43c, 0xfa217f, 0x6a9c75, 0xfb5de7, 0x25b8ea, 0x9b5bc4, 0xda9f63, 0xe23209, 0xfb899b, 0x94a6fd];
-    static GAP: number = 3;
-
-    static BACKGROUND_COLOR: number = 0xF3F3F3;
-    static TOOL_TIP_BACKGROUND_COLOR: number = 0xffffff;
-    static LIGHT_TEXT_COLOR: number = 0xffffff;
-    static LIGHT_TEXT_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.LIGHT_TEXT_COLOR);
-    static DARK_TEXT_COLOR: number = 0x282828;
-    static HIGHLIGHT_TEXT_COLOR: number = 0xffcc00;
-    static FPS_TEXT_COLOR: number = StyleConstants.DARK_TEXT_COLOR;
-    static CORRELATION_LABEL_TEXT_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.DARK_TEXT_COLOR);
-    static LOADING_SCREEN_TEXT_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.DARK_TEXT_COLOR);
-    static ERROR_COLOR: number = 0x540E25;
-    static WARNING_COLOR: number = 0xE58F24;
-    static LOWER_THAN_NAIVE_COLOR: number = 0xee0000;
-    static HIGHLIGHT_COLOR: number = 0x82A8D9;
-    static HIGHLIGHT_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.HIGHLIGHT_COLOR);
-    static OPERATOR_BACKGROUND_COLOR: number = 0x282828;
-    static LOADING_ANIMATION_COLOR: number = StyleConstants.OPERATOR_BACKGROUND_COLOR;
-    static MENU_COLOR: number = 0x282828;
-    static MENU_FONT_COLOR: number = StyleConstants.LIGHT_TEXT_COLOR;
-    static MENU_SELECTED_COLOR: number = StyleConstants.HIGHLIGHT_COLOR;
-    static MENU_SELECTED_FONT_COLOR: number = StyleConstants.LIGHT_TEXT_COLOR;
-    static BRUSH_COLOR: number = 0xff0000;
-    static DROP_ACCEPT_COLOR: number = StyleConstants.HIGHLIGHT_COLOR;
-    static SELECTED_COLOR: number = 0xffffff;
-    static SELECTED_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.SELECTED_COLOR);
-    static PROGRESS_BACKGROUND_COLOR: number = 0x595959;
-    static GRID_LINES_COLOR: number = 0x3D3D3D;
-    static GRID_LINES_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.GRID_LINES_COLOR);
-
-    static MAX_CHAR_FOR_HISTOGRAM_LABELS: number = 20;
-
-    static OVERLAP_COLOR: number = 0x0000ff;//0x540E25;
-    static BRUSH_COLORS: Array<number> = new Array<number>(
-        0xFFDA7E, 0xFE8F65, 0xDA5655, 0x8F2240
-    );
-
-    static MIN_VALUE_COLOR: number = 0x373d43; //32343d, 373d43,  3b4648
-    static MARGIN_BARS_COLOR: number = 0xffffff;
-    static MARGIN_BARS_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.MARGIN_BARS_COLOR);
-
-    static HISTOGRAM_WIDTH: number = 200;
-    static HISTOGRAM_HEIGHT: number = 150;
-    static PREDICTOR_WIDTH: number = 150;
-    static PREDICTOR_HEIGHT: number = 100;
-    static RAWDATA_WIDTH: number = 150;
-    static RAWDATA_HEIGHT: number = 100;
-    static FREQUENT_ITEM_WIDTH: number = 180;
-    static FREQUENT_ITEM_HEIGHT: number = 100;
-    static CORRELATION_WIDTH: number = 555;
-    static CORRELATION_HEIGHT: number = 390;
-    static PROBLEM_FINDER_WIDTH: number = 450;
-    static PROBLEM_FINDER_HEIGHT: number = 150;
-    static PIPELINE_OPERATOR_WIDTH: number = 300;
-    static PIPELINE_OPERATOR_HEIGHT: number = 120;
-    static SLICE_WIDTH: number = 150;
-    static SLICE_HEIGHT: number = 45;
-    static BORDER_MENU_ITEM_WIDTH: number = 50;
-    static BORDER_MENU_ITEM_HEIGHT: number = 30;
-
-
-    static SLICE_BG_COLOR: string = StyleConstants.HexToHexString(StyleConstants.OPERATOR_BACKGROUND_COLOR);
-    static SLICE_EMPTY_COLOR: number = StyleConstants.OPERATOR_BACKGROUND_COLOR;
-    static SLICE_OCCUPIED_COLOR: number = 0xffffff;
-    static SLICE_OCCUPIED_BG_COLOR: string = StyleConstants.HexToHexString(StyleConstants.OPERATOR_BACKGROUND_COLOR);
-    static SLICE_HOVER_BG_COLOR: string = StyleConstants.HexToHexString(StyleConstants.HIGHLIGHT_COLOR);
-    static SLICE_HOVER_COLOR: number = 0xffffff;
-
-    static HexToHexString(hex: number): string {
-        if (hex === undefined) {
-            return "#000000";
-        }
-        var s = hex.toString(16);
-        while (s.length < 6) {
-            s = "0" + s;
-        }
-        return "#" + s;
-    }
-
-
-} 
diff --git a/src/client/northstar/utils/Utils.ts b/src/client/northstar/utils/Utils.ts
deleted file mode 100644
index d071dec62..000000000
--- a/src/client/northstar/utils/Utils.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-import { IBaseBrushable } from '../core/brusher/IBaseBrushable';
-import { IBaseFilterConsumer } from '../core/filter/IBaseFilterConsumer';
-import { IBaseFilterProvider } from '../core/filter/IBaseFilterProvider';
-import { AggregateFunction } from '../model/idea/idea';
-
-export class Utils {
-
-    public static EqualityHelper(a: Object, b: Object): boolean {
-        if (a === b) return true;
-        if (a === undefined && b !== undefined) return false;
-        if (a === null && b !== null) return false;
-        if (b === undefined && a !== undefined) return false;
-        if (b === null && a !== null) return false;
-        if ((<any>a).constructor.name !== (<any>b).constructor.name) return false;
-        return true;
-    }
-
-    public static LowercaseFirstLetter(str: string) {
-        return str.charAt(0).toUpperCase() + str.slice(1);
-    }
-
-    //
-    // this Type Guard tests if dropTarget is an IDropTarget.  If it is, it coerces the compiler
-    // to treat the dropTarget parameter as an IDropTarget *ouside* this function scope (ie, in
-    // the scope of where this function is called from).
-    //
-
-    public static isBaseBrushable<T>(obj: Object): obj is IBaseBrushable<T> {
-        let typed = <IBaseBrushable<T>>obj;
-        return typed !== null && typed.BrusherModels !== undefined;
-    }
-
-    public static isBaseFilterProvider(obj: Object): obj is IBaseFilterProvider {
-        let typed = <IBaseFilterProvider>obj;
-        return typed !== null && typed.FilterModels !== undefined;
-    }
-
-    public static isBaseFilterConsumer(obj: Object): obj is IBaseFilterConsumer {
-        let typed = <IBaseFilterConsumer>obj;
-        return typed !== null && typed.FilterOperand !== undefined;
-    }
-
-    public static EncodeQueryData(data: any): string {
-        const ret = [];
-        for (let d in data) {
-            ret.push(encodeURIComponent(d) + "=" + encodeURIComponent(data[d]));
-        }
-        return ret.join("&");
-    }
-
-    public static ToVegaAggregationString(agg: AggregateFunction): string {
-        if (agg === AggregateFunction.Avg) {
-            return "average";
-        }
-        else if (agg === AggregateFunction.Count) {
-            return "count";
-        }
-        else {
-            return "";
-        }
-    }
-
-    public static GetQueryVariable(variable: string) {
-        let query = window.location.search.substring(1);
-        let vars = query.split("&");
-        for (const variable of vars) {
-            let pair = variable.split("=");
-            if (decodeURIComponent(pair[0]) === variable) {
-                return decodeURIComponent(pair[1]);
-            }
-        }
-        return undefined;
-    }
-}
-
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index 569c1ef6d..b3295ece0 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -10,7 +10,6 @@ import { CollectionViewType } from "../views/collections/CollectionView";
 import { Cast, CastCtor } from "../../new_fields/Types";
 import { listSpec } from "../../new_fields/Schema";
 import { AudioField, ImageField } from "../../new_fields/URLField";
-import { HistogramField } from "../northstar/dash-fields/HistogramField";
 import { Utils } from "../../Utils";
 import { RichTextField } from "../../new_fields/RichTextField";
 import { DictationOverlay } from "../views/DictationOverlay";
@@ -282,9 +281,8 @@ export namespace DictationManager {
             [DocumentType.COL, listSpec(Doc)],
             [DocumentType.AUDIO, AudioField],
             [DocumentType.IMG, ImageField],
-            [DocumentType.HIST, HistogramField],
             [DocumentType.IMPORT, listSpec(Doc)],
-            [DocumentType.TEXT, "string"]
+            [DocumentType.RTF, "string"]
         ]);
 
         const tryCast = (view: DocumentView, type: DocumentType) => {
@@ -377,7 +375,7 @@ export namespace DictationManager {
             {
                 expression: /view as (freeform|stacking|masonry|schema|tree)/g,
                 action: (target: DocumentView, matches: RegExpExecArray) => {
-                    const mode = CollectionViewType.valueOf(matches[1]);
+                    const mode = matches[1];
                     mode && (target.props.Document._viewType = mode);
                 },
                 restrictTo: [DocumentType.COL]
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index d96257ca1..7b38fdac2 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -52,7 +52,7 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
         // bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant
         if (!doc.onDragStart && !doc.isButtonBar) {
             const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc;
-            if (layoutDoc.type === DocumentType.COL || layoutDoc.type === DocumentType.TEXT || layoutDoc.type === DocumentType.IMG) {
+            if (layoutDoc.type === DocumentType.COL || layoutDoc.type === DocumentType.RTF || layoutDoc.type === DocumentType.IMG) {
                 !layoutDoc.isTemplateDoc && makeTemplate(layoutDoc);
             } else {
                 (layoutDoc.layout instanceof Doc) && !data.userDropAction;
diff --git a/src/client/util/KeyCodes.ts b/src/client/util/KeyCodes.ts
new file mode 100644
index 000000000..cacb72a57
--- /dev/null
+++ b/src/client/util/KeyCodes.ts
@@ -0,0 +1,136 @@
+/**
+ * Class contains the keycodes for keys on your keyboard.
+ *
+ * Useful for auto completion:
+ *
+ * ```
+ * switch (event.key)
+ * {
+ *      case KeyCode.UP:
+ *      {
+ *      	// Up key pressed
+ *       	break;
+ *      }
+ *      case KeyCode.DOWN:
+ *      {
+ *      	// Down key pressed
+ *       	break;
+ *      }
+ *      case KeyCode.LEFT:
+ *      {
+ *      	// Left key pressed
+ *       	break;
+ *      }
+ *      case KeyCode.RIGHT:
+ *      {
+ *      	// Right key pressed
+ *       	break;
+ *      }
+ *      default:
+ *      {
+ *      	// ignore
+ *      	break;
+ *      }
+ * }
+ * ```
+ */
+export class KeyCodes {
+    public static TAB: number = 9;
+    public static CAPS_LOCK: number = 20;
+    public static SHIFT: number = 16;
+    public static CONTROL: number = 17;
+    public static SPACE: number = 32;
+    public static DOWN: number = 40;
+    public static UP: number = 38;
+    public static LEFT: number = 37;
+    public static RIGHT: number = 39;
+    public static ESCAPE: number = 27;
+    public static F1: number = 112;
+    public static F2: number = 113;
+    public static F3: number = 114;
+    public static F4: number = 115;
+    public static F5: number = 116;
+    public static F6: number = 117;
+    public static F7: number = 118;
+    public static F8: number = 119;
+    public static F9: number = 120;
+    public static F10: number = 121;
+    public static F11: number = 122;
+    public static F12: number = 123;
+    public static INSERT: number = 45;
+    public static HOME: number = 36;
+    public static PAGE_UP: number = 33;
+    public static PAGE_DOWN: number = 34;
+    public static DELETE: number = 46;
+    public static END: number = 35;
+    public static ENTER: number = 13;
+    public static BACKSPACE: number = 8;
+    public static NUMPAD_0: number = 96;
+    public static NUMPAD_1: number = 97;
+    public static NUMPAD_2: number = 98;
+    public static NUMPAD_3: number = 99;
+    public static NUMPAD_4: number = 100;
+    public static NUMPAD_5: number = 101;
+    public static NUMPAD_6: number = 102;
+    public static NUMPAD_7: number = 103;
+    public static NUMPAD_8: number = 104;
+    public static NUMPAD_9: number = 105;
+    public static NUMPAD_DIVIDE: number = 111;
+    public static NUMPAD_ADD: number = 107;
+    public static NUMPAD_ENTER: number = 13;
+    public static NUMPAD_DECIMAL: number = 110;
+    public static NUMPAD_SUBTRACT: number = 109;
+    public static NUMPAD_MULTIPLY: number = 106;
+    public static SEMICOLON: number = 186;
+    public static EQUAL: number = 187;
+    public static COMMA: number = 188;
+    public static MINUS: number = 189;
+    public static PERIOD: number = 190;
+    public static SLASH: number = 191;
+    public static BACKQUOTE: number = 192;
+    public static LEFTBRACKET: number = 219;
+    public static BACKSLASH: number = 220;
+    public static RIGHTBRACKET: number = 221;
+    public static QUOTE: number = 222;
+    public static ALT: number = 18;
+    public static COMMAND: number = 15;
+    public static NUMPAD: number = 21;
+    public static A: number = 65;
+    public static B: number = 66;
+    public static C: number = 67;
+    public static D: number = 68;
+    public static E: number = 69;
+    public static F: number = 70;
+    public static G: number = 71;
+    public static H: number = 72;
+    public static I: number = 73;
+    public static J: number = 74;
+    public static K: number = 75;
+    public static L: number = 76;
+    public static M: number = 77;
+    public static N: number = 78;
+    public static O: number = 79;
+    public static P: number = 80;
+    public static Q: number = 81;
+    public static R: number = 82;
+    public static S: number = 83;
+    public static T: number = 84;
+    public static U: number = 85;
+    public static V: number = 86;
+    public static W: number = 87;
+    public static X: number = 88;
+    public static Y: number = 89;
+    public static Z: number = 90;
+    public static NUM_0: number = 48;
+    public static NUM_1: number = 49;
+    public static NUM_2: number = 50;
+    public static NUM_3: number = 51;
+    public static NUM_4: number = 52;
+    public static NUM_5: number = 53;
+    public static NUM_6: number = 54;
+    public static NUM_7: number = 55;
+    public static NUM_8: number = 56;
+    public static NUM_9: number = 57;
+    public static SUBSTRACT: number = 189;
+    public static ADD: number = 187;
+}
\ No newline at end of file
diff --git a/src/client/util/type_decls.d b/src/client/util/type_decls.d
index 97f6b79fb..08aec3724 100644
--- a/src/client/util/type_decls.d
+++ b/src/client/util/type_decls.d
@@ -195,7 +195,6 @@ interface DocumentOptions { }
 declare const Docs: {
     ImageDocument(url: string, options?: DocumentOptions): Doc;
     VideoDocument(url: string, options?: DocumentOptions): Doc;
-    // HistogramDocument(url:string, options?:DocumentOptions);
     TextDocument(options?: DocumentOptions): Doc;
     PdfDocument(url: string, options?: DocumentOptions): Doc;
     WebDocument(url: string, options?: DocumentOptions): Doc;
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 21eec66be..0c8ce28c3 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -9,7 +9,7 @@ import { PositionDocument } from '../../new_fields/documentSchemas';
 import { InteractionUtils } from '../util/InteractionUtils';
 
 
-///  DocComponent returns a generic React base class used by views that don't have any data extensions (e.g.,CollectionFreeFormDocumentView, DocumentView, ButtonBox)
+///  DocComponent returns a generic React base class used by views that don't have any data extensions (e.g.,CollectionFreeFormDocumentView, DocumentView, LabelBox)
 interface DocComponentProps {
     Document: Doc;
     LayoutDoc?: () => Opt<Doc>;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index e313b117f..bd72385ef 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -76,7 +76,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
             var [sptX, sptY] = transform.transformPoint(0, 0);
             let [bptX, bptY] = transform.transformPoint(documentView.props.PanelWidth(), documentView.props.PanelHeight());
             if (documentView.props.Document.type === DocumentType.LINK) {
-                const docuBox = documentView.ContentDiv!.getElementsByClassName("docuLinkBox-cont");
+                const docuBox = documentView.ContentDiv!.getElementsByClassName("linkAnchorBox-cont");
                 if (docuBox.length) {
                     const rect = docuBox[0].getBoundingClientRect();
                     sptX = rect.left;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index bef92f0fd..7c9f47fe4 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -275,7 +275,7 @@ export class MainView extends React.Component {
     defaultBackgroundColors = (doc: Doc) => {
         if (this.darkScheme) {
             switch (doc.type) {
-                case DocumentType.TEXT || DocumentType.BUTTON: return "#2d2d2d";
+                case DocumentType.RTF || DocumentType.LABEL: return "#2d2d2d";
                 case DocumentType.LINK:
                 case DocumentType.COL: {
                     if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "rgb(62,62,62)";
@@ -284,8 +284,8 @@ export class MainView extends React.Component {
             }
         } else {
             switch (doc.type) {
-                case DocumentType.TEXT: return "#f1efeb";
-                case DocumentType.BUTTON: return "lightgray";
+                case DocumentType.RTF: return "#f1efeb";
+                case DocumentType.LABEL: return "lightgray";
                 case DocumentType.LINK:
                 case DocumentType.COL: {
                     if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "lightgray";
diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx
index 1e81bb80b..0352ddaca 100644
--- a/src/client/views/ScriptBox.tsx
+++ b/src/client/views/ScriptBox.tsx
@@ -50,7 +50,7 @@ export class ScriptBox extends React.Component<ScriptBoxProps> {
     }
 
     onBlur = () => {
-        this.overlayDisposer && this.overlayDisposer();
+        this.overlayDisposer?.();
     }
 
     render() {
diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
index 4790a2ad7..799fa9d85 100644
--- a/src/client/views/SearchDocBox.tsx
+++ b/src/client/views/SearchDocBox.tsx
@@ -394,7 +394,7 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
 
     render() {
         const isEditing = this.editingMetadata;
-        return (
+        return !this.content ? (null) : (
             <div style={{ pointerEvents: "all" }}>
                 <ContentFittingDocumentView {...this.props}
                     Document={this.content}
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index ae71c54f7..82204ca7b 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -4,8 +4,9 @@ import { observer } from "mobx-react";
 import { CellInfo } from "react-table";
 import "react-table/react-table.css";
 import { emptyFunction, returnFalse, returnZero, returnOne } from "../../../Utils";
-import { Doc, DocListCast, DocListCastAsync, Field, Opt } from "../../../new_fields/Doc";
+import { Doc, DocListCast, Field, Opt } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
+import { KeyCodes } from "../../util/KeyCodes";
 import { SetupDrag, DragManager } from "../../util/DragManager";
 import { CompileScript } from "../../util/Scripting";
 import { Transform } from "../../util/Transform";
@@ -21,9 +22,7 @@ import { SelectionManager } from "../../util/SelectionManager";
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faExpand } from '@fortawesome/free-solid-svg-icons';
 import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
-import { KeyCodes } from "../../northstar/utils/KeyCodes";
 import { undoBatch } from "../../util/UndoManager";
-import { List } from "lodash";
 
 library.add(faExpand);
 
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index e835811c9..57be77fdd 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -14,7 +14,6 @@ import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
 import { ComputedField } from "../../../new_fields/ScriptField";
 import { Cast, FieldValue, NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
 import { Docs, DocumentOptions } from "../../documents/Documents";
-import { Gateway } from "../../northstar/manager/Gateway";
 import { CompileScript, Transformer, ts } from "../../util/Scripting";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
@@ -673,27 +672,6 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
         }
     }
 
-    @action
-    makeDB = async () => {
-        let csv: string = this.columns.reduce((val, col) => val + col + ",", "");
-        csv = csv.substr(0, csv.length - 1) + "\n";
-        const self = this;
-        this.childDocs.map(doc => {
-            csv += self.columns.reduce((val, col) => val + (doc[col.heading] ? doc[col.heading]!.toString() : "0") + ",", "");
-            csv = csv.substr(0, csv.length - 1) + "\n";
-        });
-        csv.substring(0, csv.length - 1);
-        const dbName = StrCast(this.props.Document.title);
-        const res = await Gateway.Instance.PostSchema(csv, dbName);
-        if (self.props.CollectionView && self.props.CollectionView.props.addDocument) {
-            const schemaDoc = await Docs.Create.DBDocument("https://www.cs.brown.edu/" + dbName, { title: dbName }, { dbDoc: self.props.Document });
-            if (schemaDoc) {
-                //self.props.CollectionView.props.addDocument(schemaDoc, false);
-                self.props.Document.schemaDoc = schemaDoc;
-            }
-        }
-    }
-
     getField = (row: number, col?: number) => {
         const docs = this.childDocs;
 
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index b066f2be3..da53888fc 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -343,7 +343,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                     const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
                     this.observer = new _global.ResizeObserver(action((entries: any) => {
                         if (this.props.Document._autoHeight && ref && this.refList.length && !SelectionManager.GetIsDragging()) {
-                            Doc.Layout(doc)._height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0)
+                            Doc.Layout(doc)._height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0);
                         }
                     }));
                     this.observer.observe(ref);
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 746b2e174..41f4fb3f0 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -99,7 +99,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                 this.props.Document.resolvedDataDoc ? this.props.Document : Doc.GetProto(this.props.Document)); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template
         }
 
-        rootSelected = (outsideReaction: boolean) => {
+        rootSelected = (outsideReaction?: boolean) => {
             return this.props.isSelected(outsideReaction) || (this.props.Document.rootDocument || this.props.Document.forceActive ? this.props.rootSelected(outsideReaction) : false);
         }
 
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index c7ab66c9f..5819c829f 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -52,39 +52,19 @@ const path = require('path');
 library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faEllipsisV, faImage, faEye as any, faCopy);
 
 export enum CollectionViewType {
-    Invalid,
-    Freeform,
-    Schema,
-    Docking,
-    Tree,
-    Stacking,
-    Masonry,
-    Multicolumn,
-    Multirow,
-    Time,
-    Carousel,
-    Linear,
-    Staff
-}
-
-export namespace CollectionViewType {
-    const stringMapping = new Map<string, CollectionViewType>([
-        ["invalid", CollectionViewType.Invalid],
-        ["freeform", CollectionViewType.Freeform],
-        ["schema", CollectionViewType.Schema],
-        ["docking", CollectionViewType.Docking],
-        ["tree", CollectionViewType.Tree],
-        ["stacking", CollectionViewType.Stacking],
-        ["masonry", CollectionViewType.Masonry],
-        ["multicolumn", CollectionViewType.Multicolumn],
-        ["multirow", CollectionViewType.Multirow],
-        ["time", CollectionViewType.Time],
-        ["carousel", CollectionViewType.Carousel],
-        ["linear", CollectionViewType.Linear],
-    ]);
-
-    export const valueOf = (value: string) => stringMapping.get(value.toLowerCase());
-    export const stringFor = (value: number) => Array.from(stringMapping.entries()).find(entry => entry[1] === value)?.[0];
+    Invalid = "invalid",
+    Freeform = "freeform",
+    Schema = "schema",
+    Docking = "docking",
+    Tree = 'tree',
+    Stacking = "stacking",
+    Masonry = "masonry",
+    Multicolumn = "multicolumn",
+    Multirow = "multirow",
+    Time = "time",
+    Carousel = "carousel",
+    Linear = "linear",
+    Staff = "staff",
 }
 
 export interface CollectionRenderProps {
@@ -110,7 +90,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
     protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
 
     get collectionViewType(): CollectionViewType | undefined {
-        const viewField = NumCast(this.props.Document._viewType);
+        const viewField = StrCast(this.props.Document._viewType);
         if (CollectionView._safeMode) {
             if (viewField === CollectionViewType.Freeform) {
                 return CollectionViewType.Tree;
@@ -119,7 +99,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
                 return CollectionViewType.Freeform;
             }
         }
-        return viewField;
+        return viewField as any as CollectionViewType;
     }
 
     active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || (this.props.rootSelected(outsideReaction) && BoolCast(this.props.Document.forceActive)) || this._isChildActive || this.props.renderDepth === 0;
@@ -394,7 +374,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
                 const params = { layoutDoc: Doc.name, dataDoc: Doc.name, };
                 newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, dataDoc, "${this.props.fieldKey}", "${facetHeader}")`, params, capturedVariables);
             }
-            Doc.AddDocToList(facetCollection, this.props.fieldKey + "-filter", newFacet);
+            newFacet && Doc.AddDocToList(facetCollection, this.props.fieldKey + "-filter", newFacet);
         }
     }
 
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 9bade1c82..7741f7d42 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -18,7 +18,6 @@ import { CollectionView } from "./CollectionView";
 import "./CollectionViewChromes.scss";
 import * as Autosuggest from 'react-autosuggest';
 import KeyRestrictionRow from "./KeyRestrictionRow";
-import { ObjectField } from "../../../new_fields/ObjectField";
 const datepicker = require('js-datepicker');
 
 interface CollectionViewChromeProps {
@@ -349,11 +348,11 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
 
     dragViewDown = (e: React.PointerEvent) => {
         setupMoveUpEvents(this, e, (e, down, delta) => {
-            const vtype = NumCast(this.props.CollectionView.props.Document._viewType) as CollectionViewType;
+            const vtype = this.props.CollectionView.collectionViewType;
             const c = {
-                params: ["target"], title: CollectionViewType.stringFor(vtype),
+                params: ["target"], title: vtype,
                 script: `this.target._viewType = ${NumCast(this.props.CollectionView.props.Document._viewType)}`,
-                immediate: (source: Doc[]) => this.target = Doc.getTemplateDoc(source?.[0]),
+                immediate: (source: Doc[]) => this.props.CollectionView.props.Document._viewType = Doc.getDocTemplate(source?.[0]),
                 initialize: emptyFunction,
             };
             DragManager.StartButtonDrag([this._viewRef.current!], c.script, StrCast(c.title),
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index afe269ec3..2f0132fec 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -54,7 +54,7 @@ export class SelectorContextMenu extends React.Component<SelectorProps> {
     getOnClick({ col, target }: { col: Doc, target: Doc }) {
         return () => {
             col = Doc.IsPrototype(col) ? Doc.MakeDelegate(col) : col;
-            if (NumCast(col._viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) {
+            if (col._viewType === CollectionViewType.Freeform) {
                 const newPanX = NumCast(target.x) + NumCast(target._width) / 2;
                 const newPanY = NumCast(target.y) + NumCast(target._height) / 2;
                 col._panX = newPanX;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index a33146388..09fc5148e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -26,8 +26,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
             action(() => {
                 setTimeout(action(() => this._opacity = 1), 0); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render()
                 setTimeout(action(() => this._opacity = 0.05), 750); // this will unhighlight the link line.
-                const acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv!.getElementsByClassName("docuLinkBox-cont") : [];
-                const bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv!.getElementsByClassName("docuLinkBox-cont") : [];
+                const acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv!.getElementsByClassName("linkAnchorBox-cont") : [];
+                const bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv!.getElementsByClassName("linkAnchorBox-cont") : [];
                 const adiv = (acont.length ? acont[0] : this.props.A.ContentDiv!);
                 const bdiv = (bcont.length ? bcont[0] : this.props.B.ContentDiv!);
                 const a = adiv.getBoundingClientRect();
@@ -43,7 +43,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
                 const afield = StrCast(this.props.A.props.Document[StrCast(this.props.A.props.layoutKey, "layout")]).indexOf("anchor1") === -1 ? "anchor2" : "anchor1";
                 const bfield = afield === "anchor1" ? "anchor2" : "anchor1";
 
-                // really hacky stuff to make the DocuLinkBox display where we want it to:
+                // really hacky stuff to make the LinkAnchorBox display where we want it to:
                 //   if there's an element in the DOM with the id of the opposite anchor, then that DOM element is a hyperlink source for the current anchor and we want to place our link box at it's top right
                 //   otherwise, we just use the computed nearest point on the document boundary to the target Document
                 const targetAhyperlink = window.document.getElementById(this.props.LinkDocs[0][Id] + (this.props.LinkDocs[0][afield] as Doc)[Id]);
@@ -81,8 +81,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
     }
 
     render() {
-        const acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv!.getElementsByClassName("docuLinkBox-cont") : [];
-        const bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv!.getElementsByClassName("docuLinkBox-cont") : [];
+        const acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv!.getElementsByClassName("linkAnchorBox-cont") : [];
+        const bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv!.getElementsByClassName("linkAnchorBox-cont") : [];
         const a = (acont.length ? acont[0] : this.props.A.ContentDiv!).getBoundingClientRect();
         const b = (bcont.length ? bcont[0] : this.props.B.ContentDiv!).getBoundingClientRect();
         const apt = Utils.closestPtBetweenRectangles(a.left, a.top, a.width, a.height,
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 49ca024a2..d12f93f15 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -43,60 +43,4 @@ export class CollectionFreeFormLinksView extends React.Component {
             {this.props.children}
         </div>;
     }
-    // _brushReactionDisposer?: IReactionDisposer;
-    // componentDidMount() {
-    //     this._brushReactionDisposer = reaction(
-    //         () => {
-    //             let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
-    //             return { doclist: doclist ? doclist : [], xs: doclist.map(d => d.x) };
-    //         },
-    //         () => {
-    //             let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
-    //             let views = doclist ? doclist.filter(doc => StrCast(doc.backgroundLayout).indexOf("istogram") !== -1) : [];
-    //             views.forEach((dstDoc, i) => {
-    //                 views.forEach((srcDoc, j) => {
-    //                     let dstTarg = dstDoc;
-    //                     let srcTarg = srcDoc;
-    //                     let x1 = NumCast(srcDoc.x);
-    //                     let x2 = NumCast(dstDoc.x);
-    //                     let x1w = NumCast(srcDoc.width, -1);
-    //                     let x2w = NumCast(dstDoc.width, -1);
-    //                     if (x1w < 0 || x2w < 0 || i === j) { }
-    //                     else {
-    //                         let findBrush = (field: (Doc | Promise<Doc>)[]) => field.findIndex(brush => {
-    //                             let bdocs = brush instanceof Doc ? Cast(brush.brushingDocs, listSpec(Doc), []) : undefined;
-    //                             return bdocs && bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false;
-    //                         });
-    //                         let brushAction = (field: (Doc | Promise<Doc>)[]) => {
-    //                             let found = findBrush(field);
-    //                             if (found !== -1) {
-    //                                 field.splice(found, 1);
-    //                             }
-    //                         };
-    //                         if (Math.abs(x1 + x1w - x2) < 20) {
-    //                             let linkDoc: Doc = new Doc();
-    //                             linkDoc.title = "Histogram Brush";
-    //                             linkDoc.linkDescription = "Brush between " + StrCast(srcTarg.title) + " and " + StrCast(dstTarg.Title);
-    //                             linkDoc.brushingDocs = new List([dstTarg, srcTarg]);
-
-    //                             brushAction = (field: (Doc | Promise<Doc>)[]) => {
-    //                                 if (findBrush(field) === -1) {
-    //                                     field.push(linkDoc);
-    //                                 }
-    //                             };
-    //                         }
-    //                         if (dstTarg.brushingDocs === undefined) dstTarg.brushingDocs = new List<Doc>();
-    //                         if (srcTarg.brushingDocs === undefined) srcTarg.brushingDocs = new List<Doc>();
-    //                         let dstBrushDocs = Cast(dstTarg.brushingDocs, listSpec(Doc), []);
-    //                         let srcBrushDocs = Cast(srcTarg.brushingDocs, listSpec(Doc), []);
-    //                         brushAction(dstBrushDocs);
-    //                         brushAction(srcBrushDocs);
-    //                     }
-    //                 });
-    //             });
-    //         });
-    // }
-    // componentWillUnmount() {
-    //     this._brushReactionDisposer?.();
-    // }
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss
index fb16b8365..53b54d7e4 100644
--- a/src/client/views/nodes/AudioBox.scss
+++ b/src/client/views/nodes/AudioBox.scss
@@ -88,7 +88,7 @@
                     opacity:0.9;
                     background-color: transparent;
                     box-shadow: black 2px 2px 1px;
-                    .docuLinkBox-cont {
+                    .linkAnchorBox-cont {
                         position: relative !important;
                         height: 100%  !important;
                         width: 100% !important;
@@ -103,7 +103,7 @@
                     box-shadow: black 1px 1px 1px;
                     margin-left: -1;
                     margin-top: -2;
-                    .docuLinkBox-cont {
+                    .linkAnchorBox-cont {
                         position: relative !important;
                         height: 100%  !important;
                         width: 100% !important;
diff --git a/src/client/views/nodes/ButtonBox.scss b/src/client/views/nodes/ButtonBox.scss
deleted file mode 100644
index 293af289d..000000000
--- a/src/client/views/nodes/ButtonBox.scss
+++ /dev/null
@@ -1,38 +0,0 @@
-.buttonBox-outerDiv {
-    width: 100%;
-    height: 100%;
-    pointer-events: all;
-    border-radius: inherit;
-    display: flex;
-    flex-direction: column;
-}
-
-.buttonBox-mainButton {
-    width: 100%;
-    height: 100%;
-    border-radius: inherit;
-    letter-spacing: 2px;
-    text-transform: uppercase;
-    overflow: hidden;
-    display:flex;
-}
-
-.buttonBox-mainButtonCenter {
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-    display: inline;
-    align-items: center;
-    margin: auto;
-}
-
-.buttonBox-params {
-    display: flex;
-    flex-direction: row;
-}
-
-.buttonBox-missingParam {
-    width: 100%;
-    background: lightgray;
-    border: dimGray solid 1px;
-}
\ No newline at end of file
diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx
deleted file mode 100644
index 1b70ff824..000000000
--- a/src/client/views/nodes/ButtonBox.tsx
+++ /dev/null
@@ -1,97 +0,0 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faEdit } from '@fortawesome/free-regular-svg-icons';
-import { action, computed } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { Doc, DocListCast } from '../../../new_fields/Doc';
-import { List } from '../../../new_fields/List';
-import { createSchema, makeInterface, listSpec } from '../../../new_fields/Schema';
-import { ScriptField } from '../../../new_fields/ScriptField';
-import { BoolCast, StrCast, Cast, FieldValue } from '../../../new_fields/Types';
-import { DragManager } from '../../util/DragManager';
-import { undoBatch } from '../../util/UndoManager';
-import { DocComponent } from '../DocComponent';
-import './ButtonBox.scss';
-import { FieldView, FieldViewProps } from './FieldView';
-import { ContextMenuProps } from '../ContextMenuItem';
-import { ContextMenu } from '../ContextMenu';
-import { documentSchema } from '../../../new_fields/documentSchemas';
-
-
-library.add(faEdit as any);
-
-const ButtonSchema = createSchema({
-    onClick: ScriptField,
-    buttonParams: listSpec("string"),
-    text: "string"
-});
-
-type ButtonDocument = makeInterface<[typeof ButtonSchema, typeof documentSchema]>;
-const ButtonDocument = makeInterface(ButtonSchema, documentSchema);
-
-@observer
-export class ButtonBox extends DocComponent<FieldViewProps, ButtonDocument>(ButtonDocument) {
-    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ButtonBox, fieldKey); }
-    private dropDisposer?: DragManager.DragDropDisposer;
-
-    @computed get dataDoc() {
-        return this.props.DataDoc &&
-            (this.Document.isTemplateForField || BoolCast(this.props.DataDoc.isTemplateForField) ||
-                this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document);
-    }
-
-
-    protected createDropTarget = (ele: HTMLDivElement) => {
-        this.dropDisposer?.();
-        if (ele) {
-            this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this));
-        }
-    }
-
-    specificContextMenu = (e: React.MouseEvent): void => {
-        const funcs: ContextMenuProps[] = [];
-        funcs.push({
-            description: "Clear Script Params", event: () => {
-                const params = FieldValue(this.Document.buttonParams);
-                params?.map(p => this.props.Document[p] = undefined);
-            }, icon: "trash"
-        });
-
-        ContextMenu.Instance.addItem({ description: "OnClick...", subitems: funcs, icon: "asterisk" });
-    }
-
-    @undoBatch
-    @action
-    drop = (e: Event, de: DragManager.DropEvent) => {
-        const docDragData = de.complete.docDragData;
-        const params = this.Document.buttonParams;
-        const missingParams = params?.filter(p => this.props.Document[p] === undefined);
-        if (docDragData && missingParams?.includes((e.target as any).textContent)) {
-            this.props.Document[(e.target as any).textContent] = new List<Doc>(docDragData.droppedDocuments.map((d, i) =>
-                d.onDragStart ? docDragData.draggedDocuments[i] : d));
-            e.stopPropagation();
-        }
-    }
-    // (!missingParams || !missingParams.length ? "" : "(" + missingParams.map(m => m + ":").join(" ") + ")")
-    render() {
-        const params = this.Document.buttonParams;
-        const missingParams = params?.filter(p => this.props.Document[p] === undefined);
-        params?.map(p => DocListCast(this.props.Document[p])); // bcz: really hacky form of prefetching ... 
-        return (
-            <div className="buttonBox-outerDiv" ref={this.createDropTarget} onContextMenu={this.specificContextMenu}
-                style={{ boxShadow: this.Document.opacity === 0 ? undefined : StrCast(this.Document.boxShadow, "") }}>
-                <div className="buttonBox-mainButton" style={{
-                    background: this.Document.backgroundColor, color: this.Document.color || "inherit",
-                    fontSize: this.Document.fontSize, letterSpacing: this.Document.letterSpacing || "", textTransform: (this.Document.textTransform as any) || ""
-                }} >
-                    <div className="buttonBox-mainButtonCenter">
-                        {(this.Document.text || this.Document.title)}
-                    </div>
-                </div>
-                <div className="buttonBox-params" >
-                    {!missingParams || !missingParams.length ? (null) : missingParams.map(m => <div key={m} className="buttonBox-missingParam">{m}</div>)}
-                </div>
-            </div>
-        );
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/nodes/DocuLinkBox.scss b/src/client/views/nodes/DocuLinkBox.scss
deleted file mode 100644
index f2c203548..000000000
--- a/src/client/views/nodes/DocuLinkBox.scss
+++ /dev/null
@@ -1,29 +0,0 @@
-.docuLinkBox-cont, .docuLinkBox-cont-small {
-    cursor: default;
-    position: absolute;
-    width: 15;
-    height: 15;
-    border-radius: 20px;
-    pointer-events: all;
-    user-select: none;
-
-    .docuLinkBox-linkCloser {
-        position: absolute;
-        width: 18;
-        height: 18;
-        background: rgb(219, 21, 21);
-        top: -1px;
-        left: -1px;
-        border-radius: 5px;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        padding-left: 2px;
-        padding-top: 1px;
-    }
-}
-
-.docuLinkBox-cont-small {
-    width:5px;
-    height:5px;
-}
\ No newline at end of file
diff --git a/src/client/views/nodes/DocuLinkBox.tsx b/src/client/views/nodes/DocuLinkBox.tsx
deleted file mode 100644
index 31ce58079..000000000
--- a/src/client/views/nodes/DocuLinkBox.tsx
+++ /dev/null
@@ -1,146 +0,0 @@
-import { action, observable } from "mobx";
-import { observer } from "mobx-react";
-import { Doc, DocListCast } from "../../../new_fields/Doc";
-import { documentSchema } from "../../../new_fields/documentSchemas";
-import { makeInterface } from "../../../new_fields/Schema";
-import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { Utils, setupMoveUpEvents } from '../../../Utils';
-import { DocumentManager } from "../../util/DocumentManager";
-import { DragManager } from "../../util/DragManager";
-import { DocComponent } from "../DocComponent";
-import "./DocuLinkBox.scss";
-import { FieldView, FieldViewProps } from "./FieldView";
-import React = require("react");
-import { ContextMenuProps } from "../ContextMenuItem";
-import { ContextMenu } from "../ContextMenu";
-import { LinkEditor } from "../linking/LinkEditor";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { SelectionManager } from "../../util/SelectionManager";
-import { TraceMobx } from "../../../new_fields/util";
-const higflyout = require("@hig/flyout");
-export const { anchorPoints } = higflyout;
-export const Flyout = higflyout.default;
-
-type DocLinkSchema = makeInterface<[typeof documentSchema]>;
-const DocLinkDocument = makeInterface(documentSchema);
-
-@observer
-export class DocuLinkBox extends DocComponent<FieldViewProps, DocLinkSchema>(DocLinkDocument) {
-    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DocuLinkBox, fieldKey); }
-    _doubleTap = false;
-    _lastTap: number = 0;
-    _ref = React.createRef<HTMLDivElement>();
-    _isOpen = false;
-    _timeout: NodeJS.Timeout | undefined;
-    @observable _x = 0;
-    @observable _y = 0;
-    @observable _selected = false;
-    @observable _editing = false;
-    @observable _forceOpen = false;
-
-    onPointerDown = (e: React.PointerEvent) => {
-        setupMoveUpEvents(this, e, this.onPointerMove, () => { }, this.onClick);
-    }
-    onPointerMove = action((e: PointerEvent, down: number[], delta: number[]) => {
-        const cdiv = this._ref && this._ref.current && this._ref.current.parentElement;
-        if (!this._isOpen && cdiv) {
-            const bounds = cdiv.getBoundingClientRect();
-            const pt = Utils.getNearestPointInPerimeter(bounds.left, bounds.top, bounds.width, bounds.height, e.clientX, e.clientY);
-            const separation = Math.sqrt((pt[0] - e.clientX) * (pt[0] - e.clientX) + (pt[1] - e.clientY) * (pt[1] - e.clientY));
-            const dragdist = Math.sqrt((pt[0] - down[0]) * (pt[0] - down[0]) + (pt[1] - down[1]) * (pt[1] - down[1]));
-            if (separation > 100) {
-                const dragData = new DragManager.DocumentDragData([this.props.Document]);
-                dragData.dropAction = "alias";
-                dragData.removeDropProperties = ["anchor1_x", "anchor1_y", "anchor2_x", "anchor2_y", "isButton"];
-                DragManager.StartDocumentDrag([this._ref.current!], dragData, down[0], down[1]);
-                return true;
-            } else if (dragdist > separation) {
-                this.props.Document[this.props.fieldKey + "_x"] = (pt[0] - bounds.left) / bounds.width * 100;
-                this.props.Document[this.props.fieldKey + "_y"] = (pt[1] - bounds.top) / bounds.height * 100;
-            }
-        }
-        return false;
-    });
-    @action
-    onClick = (e: PointerEvent) => {
-        this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0);
-        this._lastTap = Date.now();
-        if ((e.button === 2 || e.ctrlKey || !this.props.Document.isButton)) {
-            this.props.select(false);
-        }
-        if (!this._doubleTap) {
-            const anchorContainerDoc = this.props.ContainingCollectionDoc; // bcz: hack!  need a better prop for passing the anchor's container 
-            this._editing = true;
-            anchorContainerDoc && this.props.bringToFront(anchorContainerDoc, false);
-            if (anchorContainerDoc && !this.props.Document.onClick && !this._isOpen) {
-                this._timeout = setTimeout(action(() => {
-                    DocumentManager.Instance.FollowLink(this.props.Document, anchorContainerDoc, document => this.props.addDocTab(document, StrCast(this.props.Document.linkOpenLocation, "inTab")), false);
-                    this._editing = false;
-                }), 300 - (Date.now() - this._lastTap));
-            }
-        } else {
-            this._timeout && clearTimeout(this._timeout);
-            this._timeout = undefined;
-        }
-    }
-
-    openLinkDocOnRight = (e: React.MouseEvent) => {
-        this.props.addDocTab(this.props.Document, "onRight");
-    }
-    openLinkTargetOnRight = (e: React.MouseEvent) => {
-        const alias = Doc.MakeAlias(Cast(this.props.Document[this.props.fieldKey], Doc, null));
-        alias.isButton = undefined;
-        alias.isBackground = undefined;
-        alias.layoutKey = "layout";
-        this.props.addDocTab(alias, "onRight");
-    }
-    @action
-    openLinkEditor = action((e: React.MouseEvent) => {
-        SelectionManager.DeselectAll();
-        this._editing = this._forceOpen = true;
-    });
-
-    specificContextMenu = (e: React.MouseEvent): void => {
-        const funcs: ContextMenuProps[] = [];
-        funcs.push({ description: "Open Link Target on Right", event: () => this.openLinkTargetOnRight(e), icon: "eye" });
-        funcs.push({ description: "Open Link on Right", event: () => this.openLinkDocOnRight(e), icon: "eye" });
-        funcs.push({ description: "Open Link Editor", event: () => this.openLinkEditor(e), icon: "eye" });
-
-        ContextMenu.Instance.addItem({ description: "Link Funcs...", subitems: funcs, icon: "asterisk" });
-    }
-
-    render() {
-        TraceMobx();
-        const x = this.props.PanelWidth() > 1 ? NumCast(this.props.Document[this.props.fieldKey + "_x"], 100) : 0;
-        const y = this.props.PanelWidth() > 1 ? NumCast(this.props.Document[this.props.fieldKey + "_y"], 100) : 0;
-        const c = StrCast(this.props.Document.backgroundColor, "lightblue");
-        const anchor = this.props.fieldKey === "anchor1" ? "anchor2" : "anchor1";
-        const anchorScale = (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : .15;
-
-        const timecode = this.props.Document[anchor + "Timecode"];
-        const targetTitle = StrCast((this.props.Document[anchor]! as Doc).title) + (timecode !== undefined ? ":" + timecode : "");
-        const flyout = (
-            <div className="docuLinkBox-flyout" title=" " onPointerOver={() => Doc.UnBrushDoc(this.props.Document)}>
-                <LinkEditor sourceDoc={Cast(this.props.Document[this.props.fieldKey], Doc, null)} hideback={true} linkDoc={this.props.Document} showLinks={action(() => { })} />
-                {!this._forceOpen ? (null) : <div className="docuLinkBox-linkCloser" onPointerDown={action(() => this._isOpen = this._editing = this._forceOpen = false)}>
-                    <FontAwesomeIcon color="dimGray" icon={"times"} size={"sm"} />
-                </div>}
-            </div>
-        );
-        const small = this.props.PanelWidth() <= 1;
-        return <div className={`docuLinkBox-cont${small ? "-small" : ""}`} onPointerDown={this.onPointerDown} title={targetTitle} onContextMenu={this.specificContextMenu}
-            ref={this._ref} style={{
-                background: c,
-                left: !small ? `calc(${x}% - 7.5px)` : undefined,
-                top: !small ? `calc(${y}% - 7.5px)` : undefined,
-                transform: `scale(${anchorScale / this.props.ContentScaling()})`
-            }} >
-            {!this._editing && !this._forceOpen ? (null) :
-                <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout} open={this._forceOpen ? true : undefined} onOpen={() => this._isOpen = true} onClose={action(() => this._isOpen = this._forceOpen = this._editing = false)}>
-                    <span className="parentDocumentSelector-button" >
-                        <FontAwesomeIcon icon={"eye"} size={"lg"} />
-                    </span>
-                </Flyout>}
-        </div>;
-    }
-}
diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx
index 0e2685d41..4f2b3b656 100644
--- a/src/client/views/nodes/DocumentBox.tsx
+++ b/src/client/views/nodes/DocumentBox.tsx
@@ -18,12 +18,12 @@ import { TraceMobx } from "../../../new_fields/util";
 import { DocumentView } from "./DocumentView";
 import { Docs } from "../../documents/Documents";
 
-type DocBoxSchema = makeInterface<[typeof documentSchema]>;
-const DocBoxDocument = makeInterface(documentSchema);
+type DocHolderBoxSchema = makeInterface<[typeof documentSchema]>;
+const DocHolderBoxDocument = makeInterface(documentSchema);
 
 @observer
-export class DocumentBox extends DocAnnotatableComponent<FieldViewProps, DocBoxSchema>(DocBoxDocument) {
-    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DocumentBox, fieldKey); }
+export class DocHolderBox extends DocAnnotatableComponent<FieldViewProps, DocHolderBoxSchema>(DocHolderBoxDocument) {
+    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DocHolderBox, fieldKey); }
     _prevSelectionDisposer: IReactionDisposer | undefined;
     _selections: Doc[] = [];
     _curSelection = -1;
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index dc71ba280..7522af3a3 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -3,7 +3,6 @@ import { observer } from "mobx-react";
 import { Doc, Opt } from "../../../new_fields/Doc";
 import { Cast, StrCast } from "../../../new_fields/Types";
 import { OmitKeys, Without } from "../../../Utils";
-import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox";
 import DirectoryImportBox from "../../util/Import & Export/DirectoryImportBox";
 import { CollectionDockingView } from "../collections/CollectionDockingView";
 import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
@@ -11,10 +10,11 @@ import { CollectionSchemaView } from "../collections/CollectionSchemaView";
 import { CollectionView } from "../collections/CollectionView";
 import { YoutubeBox } from "./../../apis/youtube/YoutubeBox";
 import { AudioBox } from "./AudioBox";
-import { ButtonBox } from "./ButtonBox";
+import { LabelBox } from "./LabelBox";
 import { SliderBox } from "./SliderBox";
 import { LinkBox } from "./LinkBox";
-import { DocumentBox } from "./DocumentBox";
+import { ScriptingBox } from "./ScriptingBox";
+import { DocHolderBox } from "./DocumentBox";
 import { DocumentViewProps } from "./DocumentView";
 import "./DocumentView.scss";
 import { FontIconBox } from "./FontIconBox";
@@ -27,7 +27,7 @@ import { PresBox } from "./PresBox";
 import { QueryBox } from "./QueryBox";
 import { ColorBox } from "./ColorBox";
 import { DashWebRTCVideo } from "../webcam/DashWebRTCVideo";
-import { DocuLinkBox } from "./DocuLinkBox";
+import { LinkAnchorBox } from "./LinkAnchorBox";
 import { PresElementBox } from "../presentationview/PresElementBox";
 import { ScreenshotBox } from "./ScreenshotBox";
 import { VideoBox } from "./VideoBox";
@@ -109,10 +109,10 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
                 <ObserverJsxParser
                     blacklistedAttrs={[]}
                     components={{
-                        FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, ButtonBox, SliderBox, FieldView,
+                        FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, LabelBox, SliderBox, FieldView,
                         CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
-                        PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox, PresElementBox, QueryBox,
-                        ColorBox, DashWebRTCVideo, DocuLinkBox, InkingStroke, DocumentBox, LinkBox,
+                        PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, QueryBox,
+                        ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, DocHolderBox, LinkBox, ScriptingBox,
                         RecommendationsBox, ScreenshotBox
                     }}
                     bindings={this.CreateBindings()}
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index ce7bcd206..fc9ee1201 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -34,11 +34,11 @@
         overflow-y: scroll;
         height: calc(100% - 20px);
     }
-    .documentView-docuLinkAnchor {
+    .documentView-linkAnchorBoxAnchor {
         display:flex;
         overflow: hidden;
     }
-    .documentView-docuLinkWrapper {
+    .documentView-linkAnchorBoxWrapper {
         pointer-events: none;
         position: absolute;
         transform-origin: top left;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 2df5c9bbd..8ba61fb7e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -296,13 +296,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                     this: this.props.Document,
                     self: Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document,
                     thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey
-                }, console.log);// && !this.props.Document.isButton && this.select(false);
+                }, console.log);
                 if (this.props.Document !== Doc.UserDoc().undoBtn && this.props.Document !== Doc.UserDoc().redoBtn) {
                     UndoManager.RunInBatch(func, "on click");
                 } else func();
-            } else if (this.Document.type === DocumentType.BUTTON) {
-                UndoManager.RunInBatch(() => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY), "on button click");
-            } else if (this.Document.isButton) {
+            } else if (this.Document.editScriptOnClick) {
+                UndoManager.RunInBatch(() => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, StrCast(this.Document.editScriptOnClick), e.clientX, e.clientY), "on button click");
+            } else if (this.Document.isLinkButton) {
                 DocListCast(this.props.Document.links).length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey);
             } else {
                 if (this.props.Document.isTemplateForField && !(e.ctrlKey || e.button > 0)) {
@@ -327,7 +327,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             const targetFocusAfterDocFocus = () => {
                 const where = StrCast(this.Document.followLinkLocation) || followLoc;
                 const hackToCallFinishAfterFocus = () => {
-                    setTimeout(() => finished?.(), 0); // finished() needs to be called right after hackToCallFinishAfterFocus(), but there's no callback for that so we use the hacky timeout.  
+                    finished && setTimeout(finished, 0); // finished() needs to be called right after hackToCallFinishAfterFocus(), but there's no callback for that so we use the hacky timeout.  
                     return false; // we must return false here so that the zoom to the document is not reversed.  If it weren't for needing to call finished(), we wouldn't need this function at all since not having it is equivalent to returning false
                 };
                 this.props.addDocTab(doc, where) && this.props.focus(doc, true, undefined, hackToCallFinishAfterFocus); //  add the target and focus on it.
@@ -577,23 +577,23 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     @undoBatch
-    toggleButtonBehavior = (): void => {
-        if (this.Document.isButton || this.Document.onClick || this.Document.ignoreClick) {
-            this.Document.isButton = false;
+    toggleLinkButtonBehavior = (): void => {
+        if (this.Document.isLinkButton || this.Document.onClick || this.Document.ignoreClick) {
+            this.Document.isLinkButton = false;
             this.Document.ignoreClick = false;
             this.Document.onClick = undefined;
         } else {
-            this.Document.isButton = true;
+            this.Document.isLinkButton = true;
             this.Document.followLinkLocation = undefined;
         }
     }
 
     @undoBatch
     toggleFollowInPlace = (): void => {
-        if (this.Document.isButton) {
-            this.Document.isButton = false;
+        if (this.Document.isLinkButton) {
+            this.Document.isLinkButton = false;
         } else {
-            this.Document.isButton = true;
+            this.Document.isLinkButton = true;
             this.Document.followLinkLocation = "inPlace";
         }
     }
@@ -642,7 +642,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             const portal = Docs.Create.FreeformDocument([], { _width: (this.layoutDoc._width || 0) + 10, _height: this.layoutDoc._height || 0, title: StrCast(this.props.Document.title) + ".portal" });
             DocUtils.MakeLink({ doc: this.props.Document }, { doc: portal }, "portal to");
         }
-        this.Document.isButton = true;
+        this.Document.isLinkButton = true;
     }
 
     @undoBatch
@@ -727,8 +727,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" });
         onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(this, "${this.props.Document.layoutKey}")`), icon: "window-restore" });
         onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" });
-        onClicks.push({ description: this.Document.isButton ? "Remove Follow Behavior" : "Follow Link in Place", event: this.toggleFollowInPlace, icon: "concierge-bell" });
-        onClicks.push({ description: this.Document.isButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.toggleButtonBehavior, icon: "concierge-bell" });
+        onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: this.toggleFollowInPlace, icon: "concierge-bell" });
+        onClicks.push({ description: this.Document.isLinkButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.toggleLinkButtonBehavior, icon: "concierge-bell" });
         onClicks.push({ description: "Edit onClick Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", obj.x, obj.y) });
         !existingOnClick && cm.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" });
 
@@ -861,7 +861,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         await Promise.all(allDocs.map((doc: Doc) => {
             let isMainDoc: boolean = false;
             const dataDoc = Doc.GetProto(doc);
-            if (doc.type === DocumentType.TEXT) {
+            if (doc.type === DocumentType.RTF) {
                 if (dataDoc === Doc.GetProto(this.props.Document)) {
                     isMainDoc = true;
                 }
@@ -964,7 +964,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const fallback = Cast(this.props.Document.layoutKey, "string");
         return typeof fallback === "string" ? fallback : "layout";
     }
-    rootSelected = (outsideReaction: boolean) => {
+    rootSelected = (outsideReaction?: boolean) => {
         return this.isSelected(outsideReaction) || (this.props.Document.forceActive && this.props.rootSelected?.(outsideReaction) ? true : false);
     }
     childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
@@ -1026,10 +1026,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     @computed get anchors() {
         TraceMobx();
         return DocListCast(this.Document.links).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) =>
-            <div className="documentView-docuLinkWrapper" key={d[Id]}>
+            <div className="documentView-linkAnchorBoxWrapper" key={d[Id]}>
                 <DocumentView {...this.props}
                     Document={d}
-                    ContainingCollectionDoc={this.props.Document} // bcz: hack this.props.Document is not a collection  Need a better prop for passing the containing document to the DocuLinkBox
+                    ContainingCollectionDoc={this.props.Document} // bcz: hack this.props.Document is not a collection  Need a better prop for passing the containing document to the LinkAnchorBox
                     PanelWidth={this.anchorPanelWidth}
                     PanelHeight={this.anchorPanelHeight}
                     layoutKey={this.linkEndpoint(d)}
@@ -1041,7 +1041,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     @computed get innards() {
         TraceMobx();
         if (!this.props.PanelWidth()) {  // this happens when the document is a tree view label
-            return <div className="documentView-docuLinkAnchor" >
+            return <div className="documentView-linkAnchorBoxAnchor" >
                 {StrCast(this.props.Document.title)}
                 {this.anchors}
             </div>;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 37770a2e1..836d95830 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -262,7 +262,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
         if (de.complete.docDragData) {
             const draggedDoc = de.complete.docDragData.draggedDocuments.length && de.complete.docDragData.draggedDocuments[0];
             // replace text contents whend dragging with Alt
-            if (draggedDoc && draggedDoc.type === DocumentType.TEXT && !Doc.AreProtosEqual(draggedDoc, this.props.Document) && de.altKey) {
+            if (draggedDoc && draggedDoc.type === DocumentType.RTF && !Doc.AreProtosEqual(draggedDoc, this.props.Document) && de.altKey) {
                 if (draggedDoc.data instanceof RichTextField) {
                     Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new RichTextField(draggedDoc.data.Data, draggedDoc.data.Text);
                     e.stopPropagation();
@@ -1206,7 +1206,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
                     <div className={`formattedTextBox-inner${rounded}`} ref={this.createDropTarget}
                         style={{
                             padding: `${NumCast(this.Document._xMargin, 0)}px  ${NumCast(this.Document._yMargin, 0)}px`,
-                            pointerEvents: ((this.Document.isButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined
+                            pointerEvents: ((this.Document.isLinkButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined
                         }} />
                 </div>
                 {!this.props.Document._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ?
diff --git a/src/client/views/nodes/LabelBox.scss b/src/client/views/nodes/LabelBox.scss
new file mode 100644
index 000000000..ab5b2c6b3
--- /dev/null
+++ b/src/client/views/nodes/LabelBox.scss
@@ -0,0 +1,38 @@
+.labelBox-outerDiv {
+    width: 100%;
+    height: 100%;
+    pointer-events: all;
+    border-radius: inherit;
+    display: flex;
+    flex-direction: column;
+}
+
+.labelBox-mainButton {
+    width: 100%;
+    height: 100%;
+    border-radius: inherit;
+    letter-spacing: 2px;
+    text-transform: uppercase;
+    overflow: hidden;
+    display:flex;
+}
+
+.labelBox-mainButtonCenter {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    display: inline;
+    align-items: center;
+    margin: auto;
+}
+
+.labelBox-params {
+    display: flex;
+    flex-direction: row;
+}
+
+.labelBox-missingParam {
+    width: 100%;
+    background: lightgray;
+    border: dimGray solid 1px;
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
new file mode 100644
index 000000000..0ec6af93a
--- /dev/null
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -0,0 +1,97 @@
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { faEdit } from '@fortawesome/free-regular-svg-icons';
+import { action, computed } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Doc, DocListCast } from '../../../new_fields/Doc';
+import { List } from '../../../new_fields/List';
+import { createSchema, makeInterface, listSpec } from '../../../new_fields/Schema';
+import { ScriptField } from '../../../new_fields/ScriptField';
+import { BoolCast, StrCast, Cast, FieldValue } from '../../../new_fields/Types';
+import { DragManager } from '../../util/DragManager';
+import { undoBatch } from '../../util/UndoManager';
+import { DocComponent } from '../DocComponent';
+import './LabelBox.scss';
+import { FieldView, FieldViewProps } from './FieldView';
+import { ContextMenuProps } from '../ContextMenuItem';
+import { ContextMenu } from '../ContextMenu';
+import { documentSchema } from '../../../new_fields/documentSchemas';
+
+
+library.add(faEdit as any);
+
+const LabelSchema = createSchema({
+    onClick: ScriptField,
+    buttonParams: listSpec("string"),
+    text: "string"
+});
+
+type LabelDocument = makeInterface<[typeof LabelSchema, typeof documentSchema]>;
+const LabelDocument = makeInterface(LabelSchema, documentSchema);
+
+@observer
+export class LabelBox extends DocComponent<FieldViewProps, LabelDocument>(LabelDocument) {
+    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LabelBox, fieldKey); }
+    private dropDisposer?: DragManager.DragDropDisposer;
+
+    @computed get dataDoc() {
+        return this.props.DataDoc &&
+            (this.Document.isTemplateForField || BoolCast(this.props.DataDoc.isTemplateForField) ||
+                this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document);
+    }
+
+
+    protected createDropTarget = (ele: HTMLDivElement) => {
+        this.dropDisposer?.();
+        if (ele) {
+            this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this));
+        }
+    }
+
+    specificContextMenu = (e: React.MouseEvent): void => {
+        const funcs: ContextMenuProps[] = [];
+        funcs.push({
+            description: "Clear Script Params", event: () => {
+                const params = FieldValue(this.Document.buttonParams);
+                params?.map(p => this.props.Document[p] = undefined);
+            }, icon: "trash"
+        });
+
+        ContextMenu.Instance.addItem({ description: "OnClick...", subitems: funcs, icon: "asterisk" });
+    }
+
+    @undoBatch
+    @action
+    drop = (e: Event, de: DragManager.DropEvent) => {
+        const docDragData = de.complete.docDragData;
+        const params = this.Document.buttonParams;
+        const missingParams = params?.filter(p => this.props.Document[p] === undefined);
+        if (docDragData && missingParams?.includes((e.target as any).textContent)) {
+            this.props.Document[(e.target as any).textContent] = new List<Doc>(docDragData.droppedDocuments.map((d, i) =>
+                d.onDragStart ? docDragData.draggedDocuments[i] : d));
+            e.stopPropagation();
+        }
+    }
+    // (!missingParams || !missingParams.length ? "" : "(" + missingParams.map(m => m + ":").join(" ") + ")")
+    render() {
+        const params = this.Document.buttonParams;
+        const missingParams = params?.filter(p => this.props.Document[p] === undefined);
+        params?.map(p => DocListCast(this.props.Document[p])); // bcz: really hacky form of prefetching ... 
+        return (
+            <div className="labelBox-outerDiv" ref={this.createDropTarget} onContextMenu={this.specificContextMenu}
+                style={{ boxShadow: this.Document.opacity === 0 ? undefined : StrCast(this.Document.boxShadow, "") }}>
+                <div className="labelBox-mainButton" style={{
+                    background: this.Document.backgroundColor, color: this.Document.color || "inherit",
+                    fontSize: this.Document.fontSize, letterSpacing: this.Document.letterSpacing || "", textTransform: (this.Document.textTransform as any) || ""
+                }} >
+                    <div className="labelBox-mainButtonCenter">
+                        {(this.Document.text || this.Document.title)}
+                    </div>
+                </div>
+                <div className="labelBox-params" >
+                    {!missingParams || !missingParams.length ? (null) : missingParams.map(m => <div key={m} className="labelBox-missingParam">{m}</div>)}
+                </div>
+            </div>
+        );
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/LinkAnchorBox.scss b/src/client/views/nodes/LinkAnchorBox.scss
new file mode 100644
index 000000000..7b6093ebd
--- /dev/null
+++ b/src/client/views/nodes/LinkAnchorBox.scss
@@ -0,0 +1,29 @@
+.linkAnchorBox-cont, .linkAnchorBox-cont-small {
+    cursor: default;
+    position: absolute;
+    width: 15;
+    height: 15;
+    border-radius: 20px;
+    pointer-events: all;
+    user-select: none;
+
+    .linkAnchorBox-linkCloser {
+        position: absolute;
+        width: 18;
+        height: 18;
+        background: rgb(219, 21, 21);
+        top: -1px;
+        left: -1px;
+        border-radius: 5px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        padding-left: 2px;
+        padding-top: 1px;
+    }
+}
+
+.linkAnchorBox-cont-small {
+    width:5px;
+    height:5px;
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
new file mode 100644
index 000000000..770a3d0d1
--- /dev/null
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -0,0 +1,146 @@
+import { action, observable } from "mobx";
+import { observer } from "mobx-react";
+import { Doc, DocListCast } from "../../../new_fields/Doc";
+import { documentSchema } from "../../../new_fields/documentSchemas";
+import { makeInterface } from "../../../new_fields/Schema";
+import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
+import { Utils, setupMoveUpEvents } from '../../../Utils';
+import { DocumentManager } from "../../util/DocumentManager";
+import { DragManager } from "../../util/DragManager";
+import { DocComponent } from "../DocComponent";
+import "./LinkAnchorBox.scss";
+import { FieldView, FieldViewProps } from "./FieldView";
+import React = require("react");
+import { ContextMenuProps } from "../ContextMenuItem";
+import { ContextMenu } from "../ContextMenu";
+import { LinkEditor } from "../linking/LinkEditor";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { SelectionManager } from "../../util/SelectionManager";
+import { TraceMobx } from "../../../new_fields/util";
+const higflyout = require("@hig/flyout");
+export const { anchorPoints } = higflyout;
+export const Flyout = higflyout.default;
+
+type LinkAnchorSchema = makeInterface<[typeof documentSchema]>;
+const LinkAnchorDocument = makeInterface(documentSchema);
+
+@observer
+export class LinkAnchorBox extends DocComponent<FieldViewProps, LinkAnchorSchema>(LinkAnchorDocument) {
+    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkAnchorBox, fieldKey); }
+    _doubleTap = false;
+    _lastTap: number = 0;
+    _ref = React.createRef<HTMLDivElement>();
+    _isOpen = false;
+    _timeout: NodeJS.Timeout | undefined;
+    @observable _x = 0;
+    @observable _y = 0;
+    @observable _selected = false;
+    @observable _editing = false;
+    @observable _forceOpen = false;
+
+    onPointerDown = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, this.onPointerMove, () => { }, this.onClick);
+    }
+    onPointerMove = action((e: PointerEvent, down: number[], delta: number[]) => {
+        const cdiv = this._ref && this._ref.current && this._ref.current.parentElement;
+        if (!this._isOpen && cdiv) {
+            const bounds = cdiv.getBoundingClientRect();
+            const pt = Utils.getNearestPointInPerimeter(bounds.left, bounds.top, bounds.width, bounds.height, e.clientX, e.clientY);
+            const separation = Math.sqrt((pt[0] - e.clientX) * (pt[0] - e.clientX) + (pt[1] - e.clientY) * (pt[1] - e.clientY));
+            const dragdist = Math.sqrt((pt[0] - down[0]) * (pt[0] - down[0]) + (pt[1] - down[1]) * (pt[1] - down[1]));
+            if (separation > 100) {
+                const dragData = new DragManager.DocumentDragData([this.props.Document]);
+                dragData.dropAction = "alias";
+                dragData.removeDropProperties = ["anchor1_x", "anchor1_y", "anchor2_x", "anchor2_y", "isButton"];
+                DragManager.StartDocumentDrag([this._ref.current!], dragData, down[0], down[1]);
+                return true;
+            } else if (dragdist > separation) {
+                this.props.Document[this.props.fieldKey + "_x"] = (pt[0] - bounds.left) / bounds.width * 100;
+                this.props.Document[this.props.fieldKey + "_y"] = (pt[1] - bounds.top) / bounds.height * 100;
+            }
+        }
+        return false;
+    });
+    @action
+    onClick = (e: PointerEvent) => {
+        this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0);
+        this._lastTap = Date.now();
+        if ((e.button === 2 || e.ctrlKey || !this.props.Document.isLinkButton)) {
+            this.props.select(false);
+        }
+        if (!this._doubleTap) {
+            const anchorContainerDoc = this.props.ContainingCollectionDoc; // bcz: hack!  need a better prop for passing the anchor's container 
+            this._editing = true;
+            anchorContainerDoc && this.props.bringToFront(anchorContainerDoc, false);
+            if (anchorContainerDoc && !this.props.Document.onClick && !this._isOpen) {
+                this._timeout = setTimeout(action(() => {
+                    DocumentManager.Instance.FollowLink(this.props.Document, anchorContainerDoc, document => this.props.addDocTab(document, StrCast(this.props.Document.linkOpenLocation, "inTab")), false);
+                    this._editing = false;
+                }), 300 - (Date.now() - this._lastTap));
+            }
+        } else {
+            this._timeout && clearTimeout(this._timeout);
+            this._timeout = undefined;
+        }
+    }
+
+    openLinkDocOnRight = (e: React.MouseEvent) => {
+        this.props.addDocTab(this.props.Document, "onRight");
+    }
+    openLinkTargetOnRight = (e: React.MouseEvent) => {
+        const alias = Doc.MakeAlias(Cast(this.props.Document[this.props.fieldKey], Doc, null));
+        alias.isLinkButton = undefined;
+        alias.isBackground = undefined;
+        alias.layoutKey = "layout";
+        this.props.addDocTab(alias, "onRight");
+    }
+    @action
+    openLinkEditor = action((e: React.MouseEvent) => {
+        SelectionManager.DeselectAll();
+        this._editing = this._forceOpen = true;
+    });
+
+    specificContextMenu = (e: React.MouseEvent): void => {
+        const funcs: ContextMenuProps[] = [];
+        funcs.push({ description: "Open Link Target on Right", event: () => this.openLinkTargetOnRight(e), icon: "eye" });
+        funcs.push({ description: "Open Link on Right", event: () => this.openLinkDocOnRight(e), icon: "eye" });
+        funcs.push({ description: "Open Link Editor", event: () => this.openLinkEditor(e), icon: "eye" });
+
+        ContextMenu.Instance.addItem({ description: "Link Funcs...", subitems: funcs, icon: "asterisk" });
+    }
+
+    render() {
+        TraceMobx();
+        const x = this.props.PanelWidth() > 1 ? NumCast(this.props.Document[this.props.fieldKey + "_x"], 100) : 0;
+        const y = this.props.PanelWidth() > 1 ? NumCast(this.props.Document[this.props.fieldKey + "_y"], 100) : 0;
+        const c = StrCast(this.props.Document.backgroundColor, "lightblue");
+        const anchor = this.props.fieldKey === "anchor1" ? "anchor2" : "anchor1";
+        const anchorScale = (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : .15;
+
+        const timecode = this.props.Document[anchor + "Timecode"];
+        const targetTitle = StrCast((this.props.Document[anchor]! as Doc).title) + (timecode !== undefined ? ":" + timecode : "");
+        const flyout = (
+            <div className="linkAnchorBoxBox-flyout" title=" " onPointerOver={() => Doc.UnBrushDoc(this.props.Document)}>
+                <LinkEditor sourceDoc={Cast(this.props.Document[this.props.fieldKey], Doc, null)} hideback={true} linkDoc={this.props.Document} showLinks={action(() => { })} />
+                {!this._forceOpen ? (null) : <div className="linkAnchorBox-linkCloser" onPointerDown={action(() => this._isOpen = this._editing = this._forceOpen = false)}>
+                    <FontAwesomeIcon color="dimGray" icon={"times"} size={"sm"} />
+                </div>}
+            </div>
+        );
+        const small = this.props.PanelWidth() <= 1;
+        return <div className={`linkAnchorBox-cont${small ? "-small" : ""}`} onPointerDown={this.onPointerDown} title={targetTitle} onContextMenu={this.specificContextMenu}
+            ref={this._ref} style={{
+                background: c,
+                left: !small ? `calc(${x}% - 7.5px)` : undefined,
+                top: !small ? `calc(${y}% - 7.5px)` : undefined,
+                transform: `scale(${anchorScale / this.props.ContentScaling()})`
+            }} >
+            {!this._editing && !this._forceOpen ? (null) :
+                <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout} open={this._forceOpen ? true : undefined} onOpen={() => this._isOpen = true} onClose={action(() => this._isOpen = this._forceOpen = this._editing = false)}>
+                    <span className="parentDocumentSelector-button" >
+                        <FontAwesomeIcon icon={"eye"} size={"lg"} />
+                    </span>
+                </Flyout>}
+        </div>;
+    }
+}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index f8c008a2d..53ad547b6 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -9,7 +9,6 @@ import { ScriptField } from '../../../new_fields/ScriptField';
 import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
 import { PdfField, URLField } from "../../../new_fields/URLField";
 import { Utils } from '../../../Utils';
-import { KeyCodes } from '../../northstar/utils/KeyCodes';
 import { undoBatch } from '../../util/UndoManager';
 import { panZoomSchema } from '../collections/collectionFreeForm/CollectionFreeFormView';
 import { ContextMenu } from '../ContextMenu';
@@ -18,10 +17,10 @@ import { DocAnnotatableComponent } from "../DocComponent";
 import { PDFViewer } from "../pdf/PDFViewer";
 import { FieldView, FieldViewProps } from './FieldView';
 import { pageSchema } from "./ImageBox";
+import { KeyCodes } from '../../util/KeyCodes';
 import "./PDFBox.scss";
 import React = require("react");
 import { documentSchema } from '../../../new_fields/documentSchemas';
-import { url } from 'inspector';
 
 type PdfDocument = makeInterface<[typeof documentSchema, typeof panZoomSchema, typeof pageSchema]>;
 const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema);
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 73d09b4e1..e7434feaa 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -6,7 +6,7 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction
 import { observer } from "mobx-react";
 import { Doc, DocListCast } from "../../../new_fields/Doc";
 import { InkTool } from "../../../new_fields/InkField";
-import { BoolCast, Cast, FieldValue, NumCast } from "../../../new_fields/Types";
+import { BoolCast, Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
 import { returnFalse } from "../../../Utils";
 import { DocumentManager } from "../../util/DocumentManager";
 import { undoBatch } from "../../util/UndoManager";
@@ -246,7 +246,7 @@ export class PresBox extends React.Component<FieldViewProps> {
         });
     }
 
-    updateMinimize = undoBatch(action((e: React.ChangeEvent, mode: number) => {
+    updateMinimize = undoBatch(action((e: React.ChangeEvent, mode: CollectionViewType) => {
         if (BoolCast(this.props.Document.inOverlay) !== (mode === CollectionViewType.Invalid)) {
             if (this.props.Document.inOverlay) {
                 Doc.RemoveDocFromList((Doc.UserDoc().overlays as Doc), undefined, this.props.Document);
@@ -261,7 +261,7 @@ export class PresBox extends React.Component<FieldViewProps> {
         }
     }));
 
-    initializeViewAliases = (docList: Doc[], viewtype: number) => {
+    initializeViewAliases = (docList: Doc[], viewtype: CollectionViewType) => {
         const hgt = (viewtype === CollectionViewType.Tree) ? 50 : 46;
         docList.forEach(doc => {
             doc.presBox = this.props.Document; // give contained documents a reference to the presentation
@@ -283,14 +283,14 @@ export class PresBox extends React.Component<FieldViewProps> {
     @undoBatch
     viewChanged = action((e: React.ChangeEvent) => {
         //@ts-ignore
-        this.props.Document._viewType = Number(e.target.selectedOptions[0].value);
+        this.props.Document._viewType = e.target.selectedOptions[0].value;
         this.props.Document._viewType === CollectionViewType.Stacking && (this.props.Document._pivotField = undefined); // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here
         this.updateMinimize(e, Number(this.props.Document._viewType));
     });
 
     childLayoutTemplate = () => this.props.Document._viewType === CollectionViewType.Stacking ? Cast(Doc.UserDoc().presentationTemplate, Doc, null) : undefined;
     render() {
-        const mode = NumCast(this.props.Document._viewType, CollectionViewType.Invalid);
+        const mode = StrCast(this.props.Document._viewType) as CollectionViewType;
         this.initializeViewAliases(this.childDocs, mode);
         return <div className="presBox-cont" style={{ minWidth: this.props.Document.inOverlay ? 240 : undefined, pointerEvents: this.active() || this.props.Document.inOverlay ? "all" : "none" }} >
             <div className="presBox-buttons" style={{ display: this.props.Document._chromeStatus === "disabled" ? "none" : undefined }}>
diff --git a/src/client/views/nodes/ScriptingBox.scss b/src/client/views/nodes/ScriptingBox.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
new file mode 100644
index 000000000..a2dd134ed
--- /dev/null
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -0,0 +1,71 @@
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { faEdit } from '@fortawesome/free-regular-svg-icons';
+import { computed } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Doc } from '../../../new_fields/Doc';
+import { documentSchema } from '../../../new_fields/documentSchemas';
+import { CompileScript } from "../../util/Scripting";
+import { ScriptBox } from '../ScriptBox';
+import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema';
+import { ScriptField } from '../../../new_fields/ScriptField';
+import { BoolCast, ScriptCast } from '../../../new_fields/Types';
+import { DocComponent } from '../DocComponent';
+import { FieldView, FieldViewProps } from './FieldView';
+import './ScriptingBox.scss';
+import { DocumentIconContainer } from './DocumentIcon';
+
+
+library.add(faEdit as any);
+
+const ScriptingSchema = createSchema({
+    onClick: ScriptField,
+    buttonParams: listSpec("string"),
+    text: "string"
+});
+
+type ScriptingDocument = makeInterface<[typeof ScriptingSchema, typeof documentSchema]>;
+const ScriptingDocument = makeInterface(ScriptingSchema, documentSchema);
+
+@observer
+export class ScriptingBox extends DocComponent<FieldViewProps, ScriptingDocument>(ScriptingDocument) {
+    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScriptingBox, fieldKey); }
+
+    @computed get dataDoc() {
+        return this.props.DataDoc &&
+            (this.Document.isTemplateForField || BoolCast(this.props.DataDoc.isTemplateForField) ||
+                this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document);
+    }
+
+    specificContextMenu = (e: React.MouseEvent): void => { }
+
+    render() {
+        const script = ScriptCast(this.props.Document[this.props.fieldKey]);
+        let originalText: string | undefined = undefined;
+        if (script) {
+            originalText = script.script.originalScript;
+        }
+        return !(this.props.Document instanceof Doc) ? (null) :
+            <ScriptBox initialText={originalText}
+                setParams={() => { }}
+                onCancel={() => { }}
+                onSave={(text, onError) => {
+                    if (!text) {
+                        this.dataDoc[this.props.fieldKey] = undefined;
+                    } else {
+                        const script = CompileScript(text, {
+                            params: { this: Doc.name },
+                            typecheck: false,
+                            editable: true,
+                            transformer: DocumentIconContainer.getTransformer()
+                        });
+                        if (!script.compiled) {
+                            onError(script.errors.map(error => error.messageText).join("\n"));
+                        }
+                        else {
+                            this.dataDoc[this.props.fieldKey] = new ScriptField(script);
+                        }
+                    }
+                }} showDocumentIcons />;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index d384ad12f..a4a330fe6 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -132,7 +132,7 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
                         x: (this.Document.x || 0) + width, y: (this.Document.y || 0),
                         _width: 150, _height: height / width * 150, title: "--snapshot" + (this.Document.currentTimecode || 0) + " image-"
                     });
-                    imageSummary.isButton = true;
+                    imageSummary.isLinkButton = true;
                     this.props.addDocument && this.props.addDocument(imageSummary);
                     DocUtils.MakeLink({ doc: imageSummary }, { doc: this.props.Document }, "video snapshot");
                 }
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 720f09fe0..90cd64f3c 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -282,7 +282,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
             if (anno.style.height) annoDoc._height = parseInt(anno.style.height);
             if (anno.style.width) annoDoc._width = parseInt(anno.style.width);
             annoDoc.group = mainAnnoDoc;
-            annoDoc.isButton = true;
+            annoDoc.isLinkButton = true;
             annoDocs.push(annoDoc);
             anno.remove();
             mainAnnoDoc = annoDoc;
diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx
index 1c05ff864..662b37d77 100644
--- a/src/client/views/search/FilterBox.tsx
+++ b/src/client/views/search/FilterBox.tsx
@@ -33,7 +33,7 @@ export enum Keys {
 export class FilterBox extends React.Component {
 
     static Instance: FilterBox;
-    public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB];
+    public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.RTF, DocumentType.VID, DocumentType.WEB];
 
     //if true, any keywords can be used. if false, all keywords are required.
     //this also serves as an indicator if the word status filter is applied
diff --git a/src/client/views/search/IconBar.tsx b/src/client/views/search/IconBar.tsx
index 46c109934..ec942bf7c 100644
--- a/src/client/views/search/IconBar.tsx
+++ b/src/client/views/search/IconBar.tsx
@@ -26,7 +26,7 @@ library.add(faBan);
 
 @observer
 export class IconBar extends React.Component {
-    public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB];
+    public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.RTF, DocumentType.VID, DocumentType.WEB];
 
     @observable private _icons: string[] = this._allIcons;
 
diff --git a/src/client/views/search/IconButton.tsx b/src/client/views/search/IconButton.tsx
index 4f94139d9..52641c543 100644
--- a/src/client/views/search/IconButton.tsx
+++ b/src/client/views/search/IconButton.tsx
@@ -86,15 +86,13 @@ export class IconButton extends React.Component<IconButtonProps>{
                 return faMusic;
             case (DocumentType.COL):
                 return faObjectGroup;
-            case (DocumentType.HIST):
-                return faChartBar;
             case (DocumentType.IMG):
                 return faImage;
             case (DocumentType.LINK):
                 return faLink;
             case (DocumentType.PDF):
                 return faFilePdf;
-            case (DocumentType.TEXT):
+            case (DocumentType.RTF):
                 return faStickyNote;
             case (DocumentType.VID):
                 return faVideo;
@@ -158,15 +156,13 @@ export class IconButton extends React.Component<IconButtonProps>{
                 return (<FontAwesomeIcon className="fontawesome-icon" icon={faMusic} />);
             case (DocumentType.COL):
                 return (<FontAwesomeIcon className="fontawesome-icon" icon={faObjectGroup} />);
-            case (DocumentType.HIST):
-                return (<FontAwesomeIcon className="fontawesome-icon" icon={faChartBar} />);
             case (DocumentType.IMG):
                 return (<FontAwesomeIcon className="fontawesome-icon" icon={faImage} />);
             case (DocumentType.LINK):
                 return (<FontAwesomeIcon className="fontawesome-icon" icon={faLink} />);
             case (DocumentType.PDF):
                 return (<FontAwesomeIcon className="fontawesome-icon" icon={faFilePdf} />);
-            case (DocumentType.TEXT):
+            case (DocumentType.RTF):
                 return (<FontAwesomeIcon className="fontawesome-icon" icon={faStickyNote} />);
             case (DocumentType.VID):
                 return (<FontAwesomeIcon className="fontawesome-icon" icon={faVideo} />);
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 67af661c9..19a4d558e 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -128,7 +128,7 @@ export class SearchBox extends React.Component<SearchProps> {
         }
     }
 
-    public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB];
+    public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.RTF, DocumentType.VID, DocumentType.WEB];
     //if true, any keywords can be used. if false, all keywords are required.
     //this also serves as an indicator if the word status filter is applied
     @observable private _filterOpen: boolean = false;
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 0d77026ad..fe2000700 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -68,7 +68,7 @@ export class SelectorContextMenu extends React.Component<SearchItemProps> {
     getOnClick({ col, target }: { col: Doc, target: Doc }) {
         return () => {
             col = Doc.IsPrototype(col) ? Doc.MakeDelegate(col) : col;
-            if (NumCast(col._viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) {
+            if (col._viewType === CollectionViewType.Freeform) {
                 const newPanX = NumCast(target.x) + NumCast(target._width) / 2;
                 const newPanY = NumCast(target.y) + NumCast(target._height) / 2;
                 col._panX = newPanX;
@@ -178,14 +178,13 @@ export class SearchItem extends React.Component<SearchItemProps> {
         }
         const button = layoutresult.indexOf(DocumentType.PDF) !== -1 ? faFilePdf :
             layoutresult.indexOf(DocumentType.IMG) !== -1 ? faImage :
-                layoutresult.indexOf(DocumentType.TEXT) !== -1 ? faStickyNote :
+                layoutresult.indexOf(DocumentType.RTF) !== -1 ? faStickyNote :
                     layoutresult.indexOf(DocumentType.VID) !== -1 ? faFilm :
                         layoutresult.indexOf(DocumentType.COL) !== -1 ? faObjectGroup :
                             layoutresult.indexOf(DocumentType.AUDIO) !== -1 ? faMusic :
                                 layoutresult.indexOf(DocumentType.LINK) !== -1 ? faLink :
-                                    layoutresult.indexOf(DocumentType.HIST) !== -1 ? faChartBar :
-                                        layoutresult.indexOf(DocumentType.WEB) !== -1 ? faGlobeAsia :
-                                            faCaretUp;
+                                    layoutresult.indexOf(DocumentType.WEB) !== -1 ? faGlobeAsia :
+                                        faCaretUp;
         return <div onClick={action(() => { this._useIcons = false; this._displayDim = Number(SEARCH_THUMBNAIL_SIZE); })} >
             <FontAwesomeIcon icon={button} size="2x" />
         </div>;
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index d381447c5..4fc4dc1cf 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -80,7 +80,7 @@ export function DocListCastAsync(field: FieldResult, defaultValue?: Doc[]) {
 }
 
 export async function DocCastAsync(field: FieldResult): Promise<Opt<Doc>> {
-    return await Cast(field, Doc);
+    return Cast(field, Doc);
 }
 
 export function DocListCast(field: FieldResult): Doc[] {
@@ -713,7 +713,7 @@ export namespace Doc {
     export function SetUserDoc(doc: Doc) { manager._user_doc = doc; }
     export function IsBrushed(doc: Doc) {
         return computedFn(function IsBrushed(doc: Doc) {
-            return brushManager.BrushedDoc.has(doc) ||  brushManager.BrushedDoc.has(Doc.GetProto(doc));
+            return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetProto(doc));
         })(doc);
     }
     // don't bother memoizing (caching) the result if called from a non-reactive context. (plus this avoids a warning message)
@@ -919,7 +919,7 @@ Scripting.addGlobal(function curPresentationItem() {
 Scripting.addGlobal(function selectDoc(doc: any) { Doc.UserDoc().SelectedDocs = new List([doc]); });
 Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: boolean, prevValue: any) {
     const docs = DocListCast(Doc.UserDoc().SelectedDocs).
-        filter(d => !Doc.AreProtosEqual(d, container) && !d.annotationOn && d.type !== DocumentType.DOCUMENT && d.type !== DocumentType.KVP &&
+        filter(d => !Doc.AreProtosEqual(d, container) && !d.annotationOn && d.type !== DocumentType.DOCHOLDER && d.type !== DocumentType.KVP &&
             (!excludeCollections || d.type !== DocumentType.COL || !Cast(d.data, listSpec(Doc), null)));
     return docs.length ? new List(docs) : prevValue;
 });
diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts
index ad4a5a252..a5a81f4a4 100644
--- a/src/new_fields/RichTextField.ts
+++ b/src/new_fields/RichTextField.ts
@@ -4,9 +4,6 @@ import { Deserializable } from "../client/util/SerializationHelper";
 import { Copy, ToScriptString, ToPlainText, ToString } from "./FieldSymbols";
 import { scriptingGlobal } from "../client/util/Scripting";
 
-const delimiter = "\n";
-const joiner = "";
-
 @scriptingGlobal
 @Deserializable("RichTextField")
 export class RichTextField extends ObjectField {
diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts
index 4a3119aeb..8d0ddf94c 100644
--- a/src/new_fields/ScriptField.ts
+++ b/src/new_fields/ScriptField.ts
@@ -98,12 +98,15 @@ export class ScriptField extends ObjectField {
     [Copy](): ObjectField {
         return new ScriptField(this.script);
     }
+    toString() {
+        return `${this.script.originalScript}`;
+    }
 
     [ToScriptString]() {
         return "script field";
     }
     [ToString]() {
-        return "script field";
+        return this.script.originalScript;
     }
     public static CompileScript(script: string, params: object = {}, addReturn = false, capturedVariables?: { [name: string]: Field }) {
         const compiled = CompileScript(script, {
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index 03519cb94..216b63352 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -61,7 +61,7 @@ export const documentSchema = createSchema({
     fitToBox: "boolean",        // whether freeform view contents should be zoomed/panned to fill the area of the document view
     letterSpacing: "string",
     textTransform: "string",
-    childTemplateName: "string" // the name of a template to use to override the layoutKey when rendering a document in DocumentBox 
+    childTemplateName: "string" // the name of a template to use to override the layoutKey when rendering a document in DocHolderBox 
 });
 
 export const positionSchema = createSchema({
diff --git a/src/server/Message.ts b/src/server/Message.ts
index 81f63656b..01aae5de7 100644
--- a/src/server/Message.ts
+++ b/src/server/Message.ts
@@ -19,7 +19,7 @@ export class Message<T> {
 
 export enum Types {
     Number, List, Key, Image, Web, Document, Text, Icon, RichText, DocumentReference,
-    Html, Video, Audio, Ink, PDF, Tuple, HistogramOp, Boolean, Script, Templates
+    Html, Video, Audio, Ink, PDF, Tuple, Boolean, Script, Templates
 }
 
 export interface Transferable {
diff --git a/src/server/RouteManager.ts b/src/server/RouteManager.ts
index a8680c0c9..80e4a6741 100644
--- a/src/server/RouteManager.ts
+++ b/src/server/RouteManager.ts
@@ -2,7 +2,6 @@ import RouteSubscriber from "./RouteSubscriber";
 import { DashUserModel } from "./authentication/models/user_model";
 import { Request, Response, Express } from 'express';
 import { cyan, red, green } from 'colors';
-import { Utils } from "../client/northstar/utils/Utils";
 
 export enum Method {
     GET,
diff --git a/src/server/Websocket/Websocket.ts b/src/server/Websocket/Websocket.ts
index 9f9fc9619..947aa4289 100644
--- a/src/server/Websocket/Websocket.ts
+++ b/src/server/Websocket/Websocket.ts
@@ -199,7 +199,7 @@ export namespace WebSocket {
     function setField(socket: Socket, newValue: Transferable) {
         Database.Instance.update(newValue.id, newValue, () =>
             socket.broadcast.emit(MessageStore.SetField.Message, newValue));
-        if (newValue.type === Types.Text) {
+        if (newValue.type === Types.Text) {  // if the newValue has sring type, then it's suitable for searching -- pass it to SOLR
             Search.updateDocument({ id: newValue.id, data: (newValue as any).data });
         }
     }
@@ -221,6 +221,7 @@ export namespace WebSocket {
         "pdf": ["_t", "url"],
         "audio": ["_t", "url"],
         "web": ["_t", "url"],
+        "script": ["_t", value => value.script.originalScript],
         "RichTextField": ["_t", value => value.Text],
         "date": ["_d", value => new Date(value.date).toISOString()],
         "proxy": ["_i", "fieldId"],
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 529f8d56d..589055fbe 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -2,8 +2,6 @@ import { action, computed, observable, reaction } from "mobx";
 import * as rp from 'request-promise';
 import { DocServer } from "../../../client/DocServer";
 import { Docs, DocumentOptions } from "../../../client/documents/Documents";
-import { Attribute, AttributeGroup, Catalog, Schema } from "../../../client/northstar/model/idea/idea";
-import { ArrayUtil } from "../../../client/northstar/utils/ArrayUtil";
 import { UndoManager } from "../../../client/util/UndoManager";
 import { Doc, DocListCast } from "../../../new_fields/Doc";
 import { List } from "../../../new_fields/List";
@@ -419,77 +417,6 @@ export class CurrentUserUtils {
                 throw new Error("There should be a user id! Why does Dash think there isn't one?");
             }
         });
-        // try {
-        //     const getEnvironment = await fetch("/assets/env.json", { redirect: "follow", method: "GET", credentials: "include" });
-        //     NorthstarSettings.Instance.UpdateEnvironment(await getEnvironment.json());
-        //     await Gateway.Instance.ClearCatalog();
-        //     const extraSchemas = Cast(CurrentUserUtils.UserDocument.DBSchemas, listSpec("string"), []);
-        //     let extras = await Promise.all(extraSchemas.map(sc => Gateway.Instance.GetSchema("", sc)));
-        //     let catprom = CurrentUserUtils.SetNorthstarCatalog(await Gateway.Instance.GetCatalog(), extras);
-        //     // if (catprom) await Promise.all(catprom);
-        // } catch (e) {
-
-        // }
-    }
-
-    /* Northstar catalog ... really just for testing so this should eventually go away */
-    // --------------- Northstar hooks ------------- /
-    static _northstarSchemas: Doc[] = [];
-    @observable private static _northstarCatalog?: Catalog;
-    @computed public static get NorthstarDBCatalog() { return this._northstarCatalog; }
-
-    @action static SetNorthstarCatalog(ctlog: Catalog, extras: Catalog[]) {
-        CurrentUserUtils.NorthstarDBCatalog = ctlog;
-        // if (ctlog && ctlog.schemas) {
-        //     extras.map(ex => ctlog.schemas!.push(ex));
-        //     return ctlog.schemas.map(async schema => {
-        //         let schemaDocuments: Doc[] = [];
-        //         let attributesToBecomeDocs = CurrentUserUtils.GetAllNorthstarColumnAttributes(schema);
-        //         await Promise.all(attributesToBecomeDocs.reduce((promises, attr) => {
-        //             promises.push(DocServer.GetRefField(attr.displayName! + ".alias").then(action((field: Opt<Field>) => {
-        //                 if (field instanceof Doc) {
-        //                     schemaDocuments.push(field);
-        //                 } else {
-        //                     var atmod = new ColumnAttributeModel(attr);
-        //                     let histoOp = new HistogramOperation(schema.displayName!,
-        //                         new AttributeTransformationModel(atmod, AggregateFunction.None),
-        //                         new AttributeTransformationModel(atmod, AggregateFunction.Count),
-        //                         new AttributeTransformationModel(atmod, AggregateFunction.Count));
-        //                     schemaDocuments.push(Docs.Create.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! }));
-        //                 }
-        //             })));
-        //             return promises;
-        //         }, [] as Promise<void>[]));
-        //         return CurrentUserUtils._northstarSchemas.push(Docs.Create.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! }));
-        //     });
-        // }
-    }
-    public static set NorthstarDBCatalog(ctlog: Catalog | undefined) { this._northstarCatalog = ctlog; }
-
-    public static AddNorthstarSchema(schema: Schema, schemaDoc: Doc) {
-        if (this._northstarCatalog && CurrentUserUtils._northstarSchemas) {
-            this._northstarCatalog.schemas!.push(schema);
-            CurrentUserUtils._northstarSchemas.push(schemaDoc);
-            const schemas = Cast(CurrentUserUtils.UserDocument.DBSchemas, listSpec("string"), []);
-            schemas.push(schema.displayName!);
-            CurrentUserUtils.UserDocument.DBSchemas = new List<string>(schemas);
-        }
-    }
-    public static GetNorthstarSchema(name: string): Schema | undefined {
-        return !this._northstarCatalog || !this._northstarCatalog.schemas ? undefined :
-            ArrayUtil.FirstOrDefault<Schema>(this._northstarCatalog.schemas, (s: Schema) => s.displayName === name);
-    }
-    public static GetAllNorthstarColumnAttributes(schema: Schema) {
-        const recurs = (attrs: Attribute[], g?: AttributeGroup) => {
-            if (g && g.attributes) {
-                attrs.push.apply(attrs, g.attributes);
-                if (g.attributeGroups) {
-                    g.attributeGroups.forEach(ng => recurs(attrs, ng));
-                }
-            }
-            return attrs;
-        };
-        return recurs([] as Attribute[], schema ? schema.rootAttributeGroup : undefined);
     }
 }
 
diff --git a/src/server/updateProtos.ts b/src/server/updateProtos.ts
index 90490eb45..e9860bd61 100644
--- a/src/server/updateProtos.ts
+++ b/src/server/updateProtos.ts
@@ -1,8 +1,7 @@
 import { Database } from "./database";
 
 const protos =
-    ["text", "histogram", "image", "web", "collection", "kvp",
-        "video", "audio", "pdf", "icon", "import", "linkdoc"];
+    ["text", "image", "web", "collection", "kvp", "video", "audio", "pdf", "icon", "import", "linkdoc"];
 
 (async function () {
     await Promise.all(
-- 
cgit v1.2.3-70-g09d2


From 290feed8a7c2ae700bac0d720874abc511e6cd36 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 12 Apr 2020 20:14:31 -0400
Subject: fixed nudging stoppropagation stuff.  fixed inPlace addDocTab for non
 freeform views

---
 src/client/views/PreviewCursor.tsx                 | 22 ++++++++++++++--------
 .../views/collections/CollectionStackingView.tsx   |  9 ++++++++-
 .../CollectionMulticolumnView.tsx                  |  9 +++++++++
 .../CollectionMultirowView.tsx                     | 10 ++++++++++
 4 files changed, 41 insertions(+), 9 deletions(-)

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

diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index fad2f2f0a..ecebadd2a 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -89,14 +89,20 @@ export class PreviewCursor extends React.Component<{}> {
                 PreviewCursor.Visible && PreviewCursor._onKeyPress?.(e);
                 PreviewCursor.Visible = false;
             }
-        } else if (e.key === "ArrowRight") {
-            PreviewCursor._nudge?.(1, 0);
-        } else if (e.key === "ArrowLeft") {
-            PreviewCursor._nudge?.(-1, 0);
-        } else if (e.key === "ArrowUp") {
-            PreviewCursor._nudge?.(0, 1);
-        } else if (e.key === "ArrowDown") {
-            PreviewCursor._nudge?.(0, -1);
+        } else if (PreviewCursor.Visible) {
+            if (e.key === "ArrowRight") {
+                PreviewCursor._nudge?.(1 * (e.shiftKey ? 2 : 1), 0);
+                e.stopPropagation();
+            } else if (e.key === "ArrowLeft") {
+                PreviewCursor._nudge?.(-1 * (e.shiftKey ? 2 : 1), 0);
+                e.stopPropagation();
+            } else if (e.key === "ArrowUp") {
+                PreviewCursor._nudge?.(0, 1 * (e.shiftKey ? 2 : 1));
+                e.stopPropagation();
+            } else if (e.key === "ArrowDown") {
+                PreviewCursor._nudge?.(0, -1 * (e.shiftKey ? 2 : 1));
+                e.stopPropagation();
+            }
         }
     }
 
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index da53888fc..dd84c4d6e 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -153,6 +153,13 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
     @computed get onClickHandler() { return ScriptCast(this.Document.onChildClick); }
 
+    addDocTab = (doc: Doc, where: string) => {
+        if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
+            this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
+            return true;
+        }
+        return this.props.addDocTab(doc, where);
+    }
     getDisplayDoc(doc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) {
         const layoutDoc = Doc.Layout(doc, this.props.childLayoutTemplate?.());
         const height = () => this.getDocHeight(doc);
@@ -181,7 +188,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             removeDocument={this.props.removeDocument}
             active={this.props.active}
             whenActiveChanged={this.props.whenActiveChanged}
-            addDocTab={this.props.addDocTab}
+            addDocTab={this.addDocTab}
             pinToPres={this.props.pinToPres}>
         </ContentFittingDocumentView>;
     }
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 7e511ae34..0e1cc2010 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -204,6 +204,14 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
 
     @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
 
+
+    addDocTab = (doc: Doc, where: string) => {
+        if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
+            this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
+            return true;
+        }
+        return this.props.addDocTab(doc, where);
+    }
     getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) {
         return <ContentFittingDocumentView
             {...this.props}
@@ -211,6 +219,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
             DataDocument={layout.resolvedDataDoc as Doc}
             NativeHeight={returnZero}
             NativeWidth={returnZero}
+            addDocTab={this.addDocTab}
             fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
             FreezeDimensions={BoolCast(this.props.Document._freezeChildDimensions)}
             backgroundColor={this.props.backgroundColor}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index daf1fda6c..1eb486c4f 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -14,6 +14,7 @@ import HeightLabel from './MultirowHeightLabel';
 import ResizeBar from './MultirowResizer';
 import { undoBatch } from '../../../util/UndoManager';
 import { DragManager } from '../../../util/DragManager';
+import { List } from '../../../../new_fields/List';
 
 type MultirowDocument = makeInterface<[typeof documentSchema]>;
 const MultirowDocument = makeInterface(documentSchema);
@@ -203,6 +204,14 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
 
     @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
 
+
+    addDocTab = (doc: Doc, where: string) => {
+        if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
+            this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
+            return true;
+        }
+        return this.props.addDocTab(doc, where);
+    }
     getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) {
         return <ContentFittingDocumentView
             {...this.props}
@@ -210,6 +219,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
             DataDocument={layout.resolvedDataDoc as Doc}
             NativeHeight={returnZero}
             NativeWidth={returnZero}
+            addDocTab={this.addDocTab}
             fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
             FreezeDimensions={BoolCast(this.props.Document._freezeChildDimensions)}
             backgroundColor={this.props.backgroundColor}
-- 
cgit v1.2.3-70-g09d2


From b7c1c6890c9186578ce06e8c31cdd82662d1c934 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 18 Apr 2020 23:25:15 -0400
Subject: changed structure of template docs in sidebar. got rid of special
 context menu in tree view in favor of pushing everything to document context
 menus which ca now be extended by the local document or through props.

---
 src/client/documents/Documents.ts                  |   1 +
 src/client/util/DocumentManager.ts                 |   2 +-
 src/client/views/MainView.scss                     |   2 +
 src/client/views/MainView.tsx                      |  15 +-
 .../views/collections/CollectionStackingView.tsx   |   2 +-
 .../views/collections/CollectionTreeView.tsx       |  46 ++----
 src/client/views/nodes/DocumentView.scss           |   1 -
 src/client/views/nodes/DocumentView.tsx            |  26 ++--
 .../authentication/models/current_user_utils.ts    | 159 ++++++++++++---------
 9 files changed, 136 insertions(+), 118 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 3ac823bb0..3073707a6 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -79,6 +79,7 @@ export interface DocumentOptions {
     x?: number;
     y?: number;
     z?: number;
+    author?: string;
     dropAction?: dropActionType;
     childDropAction?: dropActionType;
     layoutKey?: string;
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index e66e67723..4683e77a8 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -241,4 +241,4 @@ export class DocumentManager {
         }
     }
 }
-Scripting.addGlobal(function focus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, true)); });
\ No newline at end of file
+Scripting.addGlobal(function DocFocus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, true)); });
\ No newline at end of file
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index e9f2248ad..81d427f64 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -5,6 +5,7 @@
 .mainView-tabButtons {
     position: relative;
     width: 100%;
+    margin-top: 10px;
 }
 
 .mainContent-div {
@@ -72,6 +73,7 @@
     flex-direction: column;
     position: relative;
     height: 100%;
+    background: dimgray;
 
     .documentView-node-topmost {
         background: lightgrey;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index aec1f960a..40cabcf83 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,5 +1,5 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { faTerminal, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons';
+import { faTerminal, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
@@ -41,11 +41,12 @@ import { RadialMenu } from './nodes/RadialMenu';
 import { OverlayView } from './OverlayView';
 import PDFMenu from './pdf/PDFMenu';
 import { PreviewCursor } from './PreviewCursor';
+import { ScriptField } from '../../new_fields/ScriptField';
 
 @observer
 export class MainView extends React.Component {
     public static Instance: MainView;
-    private _buttonBarHeight = 35;
+    private _buttonBarHeight = 26;
     private _flyoutSizeOnDown = 0;
     private _urlState: HistoryUtil.DocUrl;
     private _docBtnRef = React.createRef<HTMLDivElement>();
@@ -102,7 +103,10 @@ export class MainView extends React.Component {
         }
 
         library.add(faTerminal);
+        library.add(faWindowMaximize);
         library.add(faFileAlt);
+        library.add(faAddressCard);
+        library.add(faQuestionCircle);
         library.add(faStickyNote);
         library.add(faFont);
         library.add(faExclamation);
@@ -212,6 +216,11 @@ export class MainView extends React.Component {
         const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions);
         Doc.AddDocToList(Doc.GetProto(CurrentUserUtils.UserDocument.documents as Doc), "data", freeformDoc);
         const mainDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().documents as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row");
+
+        const toggleTheme = ScriptField.MakeScript(`self.darkScheme = !self.darkScheme`);
+        mainDoc.contextMenuScripts = new List<ScriptField>([toggleTheme!]);
+        mainDoc.contextMenuLabels = new List<string>(["Toggle Theme Colors"]);
+
         Doc.AddDocToList(workspaces, "data", mainDoc);
         // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container)
         setTimeout(() => this.openWorkspace(mainDoc), 0);
@@ -459,7 +468,7 @@ export class MainView extends React.Component {
     }
 
     @computed get mainContent() {
-        const sidebar = this.userDoc && this.userDoc.sidebarContainer;
+        const sidebar = this.userDoc?.sidebarContainer;
         return !this.userDoc || !(sidebar instanceof Doc) ? (null) : (
             <div className="mainView-mainContent" style={{ color: this.darkScheme ? "rgb(205,205,205)" : "black" }} >
                 <div className="mainView-flyoutContainer" onPointerLeave={this.pointerLeaveDragger} style={{ width: this.flyoutWidth }}>
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index dd84c4d6e..b15649d83 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -63,7 +63,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             const dxf = () => this.getDocTransform(d, dref.current!);
             this._docXfs.push({ dxf: dxf, width: width, height: height });
             const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap);
-            const style = this.isStackingView ? { width: width(), marginTop: this.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` };
+            const style = this.isStackingView ? { width: width(), marginTop: i ? this.gridGap : 0, height: height() } : { gridRowEnd: `span ${rowSpan}` };
             return <div className={`collectionStackingView-${this.isStackingView ? "columnDoc" : "masonryDoc"}`} key={d[Id]} ref={dref} style={style} >
                 {this.getDisplayDoc(d, (!d.isTemplateDoc && !d.isTemplateForField && !d.PARAMS) ? undefined : this.props.DataDoc, dxf, width)}
             </div>;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 5ff8c11ee..2df1614de 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -32,7 +32,7 @@ import { Templates } from '../Templates';
 import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView";
 import "./CollectionTreeView.scss";
 import React = require("react");
-import { CollectionViewType } from './CollectionView';
+import { CollectionViewType, CollectionView } from './CollectionView';
 import { RichTextField } from '../../../new_fields/RichTextField';
 import { DocumentView } from '../nodes/DocumentView';
 
@@ -210,33 +210,6 @@ class TreeView extends React.Component<TreeViewProps> {
         })}
     />)
 
-    onWorkspaceContextMenu = (e: React.MouseEvent): void => {
-        if (!e.isPropagationStopped()) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view
-            const sort = this.props.document[`${this.fieldKey}-sortAscending`];
-            if (this.props.document === CurrentUserUtils.UserDocument.recentlyClosed) {
-                ContextMenu.Instance.addItem({ description: "Clear All", event: () => Doc.GetProto(CurrentUserUtils.UserDocument.recentlyClosed as Doc).data = new List<Doc>(), icon: "plus" });
-            } else if (this.props.document !== CurrentUserUtils.UserDocument.workspaces) {
-                ContextMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.document), icon: "tv" });
-                ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, "inTab", this.props.libraryPath), icon: "folder" });
-                ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, "onRight", this.props.libraryPath), icon: "caret-square-right" });
-                if (DocumentManager.Instance.getDocumentViews(this.dataDoc).length) {
-                    ContextMenu.Instance.addItem({ description: "Focus", event: () => (view => view && view.props.focus(this.props.document, true))(DocumentManager.Instance.getFirstDocumentView(this.props.document)), icon: "camera" });
-                }
-                ContextMenu.Instance.addItem({ description: "Delete Item", event: () => this.props.deleteDoc(this.props.document), icon: "trash-alt" });
-            } else {
-                ContextMenu.Instance.addItem({ description: "Delete Workspace", event: () => this.props.deleteDoc(this.props.document), icon: "trash-alt" });
-                ContextMenu.Instance.addItem({ description: "Create New Workspace", event: () => MainView.Instance.createNewWorkspace(), icon: "plus" });
-            }
-            ContextMenu.Instance.addItem({ description: (sort ? "Sort Descending" : (sort === false ? "Unsort" : "Sort Ascending")), event: () => this.props.document[`${this.fieldKey}-sortAscending`] = (sort ? false : (sort === false ? undefined : true)), icon: "minus" });
-            ContextMenu.Instance.addItem({ description: "Toggle Theme Colors", event: () => this.props.document.darkScheme = !this.props.document.darkScheme, icon: "minus" });
-            ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { const kvp = Docs.Create.KVPDocument(this.props.document, { _width: 300, _height: 300 }); this.props.addDocTab(kvp, "onRight"); }, icon: "layer-group" });
-            ContextMenu.Instance.addItem({ description: "Publish", event: () => DocUtils.Publish(this.props.document, StrCast(this.props.document.title), () => { }, () => { }), icon: "file" });
-            ContextMenu.Instance.displayMenu(e.pageX > 156 ? e.pageX - 156 : 0, e.pageY - 15);
-            e.stopPropagation();
-            e.preventDefault();
-        }
-    }
-
     @undoBatch
     treeDrop = (e: Event, de: DragManager.DropEvent) => {
         const pt = [de.x, de.y];
@@ -356,7 +329,11 @@ class TreeView extends React.Component<TreeViewProps> {
             const remDoc = (doc: Doc) => this.remove(doc, expandKey);
             const addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, false, true);
             const docs = expandKey === "links" ? this.childLinks : this.childDocs;
-            return <ul key={expandKey + "more"}>
+            const sortKey = `${this.fieldKey}-sortAscending`;
+            return <ul key={expandKey + "more"} onClick={(e) => {
+                this.props.document[sortKey] = (this.props.document[sortKey] ? false : (this.props.document[sortKey] === false ? undefined : true));
+                e.stopPropagation();
+            }}>
                 {!docs ? (null) :
                     TreeView.GetChildElements(docs, this.props.treeViewId, Doc.Layout(this.props.document),
                         this.templateDataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
@@ -421,6 +398,12 @@ class TreeView extends React.Component<TreeViewProps> {
             {<FontAwesomeIcon icon={checked === "check" ? "check" : (checked === "x" ? "times" : checked === "unchecked" ? "square" : !this.treeViewOpen ? (this.childDocs ? "caret-square-right" : "caret-right") : (this.childDocs ? "caret-square-down" : "caret-down"))} />}
         </div>;
     }
+
+    focusOnDoc = (doc: Doc) => DocumentManager.Instance.getFirstDocumentView(doc)?.props.focus(doc, true);
+    contextMenuItems = () => {
+        const focusScript = ScriptField.MakeFunction(`DocFocus(self)`);
+        return [{ script: focusScript!, label: "Focus" }];
+    }
     /**
      * Renders the EditableView title element for placement into the tree.
      */
@@ -442,7 +425,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 })}>
                 {this.treeViewExpandedView}
             </span>);
-        const openRight = (<div className="treeViewItem-openRight" onPointerDown={this.onPointerDown} onClick={this.openRight}>
+        const openRight = (<div className="treeViewItem-openRight" onClick={this.openRight}>
             <FontAwesomeIcon title="open in pane on right" icon="angle-right" size="lg" />
         </div>);
         return <>
@@ -474,6 +457,7 @@ class TreeView extends React.Component<TreeViewProps> {
                         PanelHeight={returnZero}
                         NativeHeight={returnZero}
                         NativeWidth={returnZero}
+                        contextMenuItems={this.contextMenuItems}
                         renderDepth={1}
                         focus={emptyFunction}
                         parentActive={returnTrue}
@@ -491,7 +475,7 @@ class TreeView extends React.Component<TreeViewProps> {
 
     render() {
         setTimeout(() => runInAction(() => untracked(() => this._overrideTreeViewOpen = this.treeViewOpen)), 0);
-        return <div className="treeViewItem-container" ref={this.createTreeDropTarget} onContextMenu={this.onWorkspaceContextMenu}>
+        return <div className="treeViewItem-container" ref={this.createTreeDropTarget}>
             <li className="collection-child">
                 <div className="treeViewItem-header" ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
                     {this.renderBullet}
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 81ae36cc0..692493414 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -71,7 +71,6 @@
         display: inline-block;
         width: 100%;
         height: 100%;
-        pointer-events: none;
 
         .documentView-styleContentWrapper {
             width: 100%;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index e3013698d..12f5b27e1 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,21 +1,24 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 import * as fa from '@fortawesome/free-solid-svg-icons';
-import { action, computed, runInAction, trace, observable } from "mobx";
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import * as rp from "request-promise";
-import { Doc, DocListCast, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc";
+import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc";
 import { Document, PositionDocument } from '../../../new_fields/documentSchemas';
 import { Id } from '../../../new_fields/FieldSymbols';
 import { InkTool } from '../../../new_fields/InkField';
 import { RichTextField } from '../../../new_fields/RichTextField';
 import { listSpec } from "../../../new_fields/Schema";
+import { SchemaHeaderField } from '../../../new_fields/SchemaHeaderField';
 import { ScriptField } from '../../../new_fields/ScriptField';
 import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
 import { AudioField, ImageField, PdfField, VideoField } from '../../../new_fields/URLField';
 import { TraceMobx } from '../../../new_fields/util';
 import { GestureUtils } from '../../../pen-gestures/GestureUtils';
-import { emptyFunction, returnOne, returnTransparent, returnTrue, Utils, OmitKeys, returnZero } from "../../../Utils";
+import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils } from "../../../Utils";
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
+import { ClientRecommender } from '../../ClientRecommender';
 import { DocServer } from "../../DocServer";
 import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents";
 import { DocumentType } from '../../documents/DocumentTypes';
@@ -24,6 +27,7 @@ import { DocumentManager } from "../../util/DocumentManager";
 import { DragManager, dropActionType } from "../../util/DragManager";
 import { InteractionUtils } from '../../util/InteractionUtils';
 import { Scripting } from '../../util/Scripting';
+import { SearchUtil } from '../../util/SearchUtil';
 import { SelectionManager } from "../../util/SelectionManager";
 import SharingManager from '../../util/SharingManager';
 import { Transform } from "../../util/Transform";
@@ -35,19 +39,13 @@ import { ContextMenuProps } from '../ContextMenuItem';
 import { DocComponent } from "../DocComponent";
 import { EditableView } from '../EditableView';
 import { InkingControl } from '../InkingControl';
+import { KeyphraseQueryView } from '../KeyphraseQueryView';
 import { OverlayView } from '../OverlayView';
-import { ScriptBox } from '../ScriptBox';
 import { ScriptingRepl } from '../ScriptingRepl';
 import { DocumentContentsView } from "./DocumentContentsView";
 import "./DocumentView.scss";
-import React = require("react");
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { SchemaHeaderField } from '../../../new_fields/SchemaHeaderField';
-import { ClientRecommender } from '../../ClientRecommender';
-import { SearchUtil } from '../../util/SearchUtil';
 import { RadialMenu } from './RadialMenu';
-import { KeyphraseQueryView } from '../KeyphraseQueryView';
-import { undo } from 'prosemirror-history';
+import React = require("react");
 
 library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight,
     fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale,
@@ -65,6 +63,7 @@ export interface DocumentViewProps {
     LayoutDoc?: () => Opt<Doc>;
     LibraryPath: Doc[];
     fitToBox?: boolean;
+    contextMenuItems?: () => { script: ScriptField, label: string }[];
     rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected
     onClick?: ScriptField;
     onPointerDown?: ScriptField;
@@ -720,6 +719,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const cm = ContextMenu.Instance;
         const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layoutKey)], Doc, null);
 
+        const customScripts = Cast(this.props.Document.contextMenuScripts, listSpec(ScriptField), []);
+        Cast(this.props.Document.contextMenuLabels, listSpec("string"), []).forEach((label, i) =>
+            cm.addItem({ description: label, event: () => customScripts[i]?.script.run({ this: this.layoutDoc, self: this.rootDoc }), icon: "sticky-note" }));
+        this.props.contextMenuItems?.().forEach(item =>
+            cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.layoutDoc, self: this.rootDoc }), icon: "sticky-note" }));
         const existing = cm.findByDescription("Layout...");
         const layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : [];
         layoutItems.push({ description: this.Document.isBackground ? "As Foreground" : "As Background", event: (e) => this.toggleBackground(false), icon: this.Document.lockedPosition ? "unlock" : "lock" });
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 32cce9608..e7a163a3e 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -18,6 +18,7 @@ import { makeTemplate } from "../../../client/util/DropConverter";
 import { RichTextField } from "../../../new_fields/RichTextField";
 import { PrefetchProxy } from "../../../new_fields/Proxy";
 import { FormattedTextBox } from "../../../client/views/nodes/FormattedTextBox";
+import { MainView } from "../../../client/views/MainView";
 
 export class CurrentUserUtils {
     private static curr_id: string;
@@ -51,7 +52,17 @@ export class CurrentUserUtils {
         ];
         doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" });
         Doc.addFieldEnumerations(Doc.GetProto(noteTemplates[4]), "taskStatus", taskStatusValues);
-        doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt, true, StrCast(nt.style)) ? nt : nt), { title: "Note Layouts", _height: 75 }));
+        doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt, true, StrCast(nt.style)) ? nt : nt), { title: "Note Layouts", _height: 75 }))
+        doc.templateButtons = Docs.Create.MasonryDocument(CurrentUserUtils.setupTemplateButtons(doc), {
+            title: "template buttons",
+            _pivotField: "author", _xMargin: 0,
+            _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled",
+            dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
+        });
+        doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([doc.noteTypes as any as Doc, doc.templateButtons as Doc, doc.clickFuncs as Doc], {
+            title: "template layouts", _xPadding: 0,
+            dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name })
+        }));
     }
     static setupDefaultIconTypes(doc: Doc, buttons?: string[]) {
         doc.iconView = new PrefetchProxy(Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(this)") }));
@@ -86,7 +97,7 @@ export class CurrentUserUtils {
             // { title: "use stamp", icon: "stamp", click: 'activateStamp(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc },
             // { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc },
             // { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc },
-            { title: "Drag a search box", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' },
+            { title: "Drag a search box", icon: "search", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' },
             { title: "Drag a document previewer", icon: "expand", ignoreClick: true, drag: 'Docs.Create.DocumentDocument(ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]"), { _width: 250, _height: 250, title: "container" })' },
             // { title: "buxton", icon: "cloud-upload-alt", ignoreClick: true, drag: "Docs.Create.Buxton()" },
         ];
@@ -94,6 +105,7 @@ export class CurrentUserUtils {
             _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100,
             icon: data.icon,
             title: data.title,
+            author: "Draggable Items",
             ignoreClick: data.ignoreClick,
             dropAction: data.click ? "copy" : undefined,
             onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined,
@@ -105,22 +117,40 @@ export class CurrentUserUtils {
         }));
     }
 
+    static setupTemplateButtons(doc: Doc) {
+        const queryTemplate = Docs.Create.MulticolumnDocument(
+            [
+                Docs.Create.QueryDocument({ title: "query", _height: 200, forceActive: true }),
+                Docs.Create.FreeformDocument([], { title: "data", _height: 100, _LODdisable: true, forceActive: true })
+            ],
+            { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true });
+        queryTemplate.isTemplateDoc = makeTemplate(queryTemplate);
+        const slideTemplate = Docs.Create.MultirowDocument(
+            [
+                Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, forceActive: true }),
+                Docs.Create.TextDocument("", { title: "text", _height: 100, forceActive: true })
+            ],
+            { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true });
+        slideTemplate.isTemplateDoc = makeTemplate(slideTemplate);
+        const descriptionTemplate = Docs.Create.TextDocument("", { title: "text", _height: 100, _showTitle: "title" });
+        Doc.GetProto(descriptionTemplate).layout = FormattedTextBox.LayoutString("description");
+        descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView");
+
+        doc.slidesBtn = CurrentUserUtils.ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, author: "-Template Items", removeDropProperties: new List<string>(["dropAction"]), title: "presentation slide", icon: "address-card" });
+        doc.descriptionBtn = CurrentUserUtils.ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: descriptionTemplate, author: "-Template Items", removeDropProperties: new List<string>(["dropAction"]), title: "description view", icon: "window-maximize" });
+        doc.queryBtn = CurrentUserUtils.ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: queryTemplate, author: "-Template Items", removeDropProperties: new List<string>(["dropAction"]), title: "query view", icon: "question-circle" });
+
+        return [doc.slidesBtn as Doc, doc.descriptionBtn as Doc, doc.queryBtn as Doc];
+    }
+
+
     static async updateCreatorButtons(doc: Doc) {
-        const toolsBtn = await Cast(doc.ToolsBtn, Doc);
-        if (toolsBtn) {
-            const stackingDoc = await Cast(toolsBtn.sourcePanel, Doc);
-            if (stackingDoc) {
-                const stackdocs = await Cast(stackingDoc.data, listSpec(Doc));
-                if (stackdocs) {
-                    const dragset = await Cast(stackdocs[0], Doc);
-                    if (dragset) {
-                        const dragdocs = await Cast(dragset.data, listSpec(Doc));
-                        if (dragdocs) {
-                            const dragDocs = await Promise.all(dragdocs);
-                            this.setupCreatorButtons(doc, dragDocs.map(d => StrCast(d.title))).map(nb => Doc.AddDocToList(dragset, "data", nb));
-                        }
-                    }
-                }
+        const dragset = await Cast(doc.dragCreators, Doc);
+        if (dragset) {
+            const dragdocs = await Cast(dragset.data, listSpec(Doc));
+            if (dragdocs) {
+                const dragDocs = await Promise.all(dragdocs);
+                this.setupCreatorButtons(doc, dragDocs.map(d => StrCast(d.title))).map(nb => Doc.AddDocToList(dragset, "data", nb));
             }
         }
     }
@@ -203,9 +233,16 @@ export class CurrentUserUtils {
     // setup the Creator button which will display the creator panel.  This panel will include the drag creators and the color picker.  when clicked, this panel will be displayed in the target container (ie, sidebarContainer)  
     static setupToolsPanel(sidebarContainer: Doc, doc: Doc) {
         // setup a masonry view of all he creators
-        const dragCreators = Docs.Create.MasonryDocument(CurrentUserUtils.setupCreatorButtons(doc), {
-            _width: 500, _autoHeight: true, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons",
-            dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), _yMargin: 5
+        const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc);
+        doc.dragCreators = Docs.Create.MasonryDocument(creatorBtns, {
+            title: "drag Creators",
+            _pivotField: "author", _xMargin: 0,
+            _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled",
+            dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
+        });
+        doc.allCreators = Docs.Create.StackingDocument([doc.dragCreators as any as Doc, doc.templateButtons as any as Doc], {
+            title: "all Creators", _yMargin: 0, _autoHeight: true, _xMargin: 0,
+            _width: 500, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled",
         });
         // setup a color picker
         const color = Docs.Create.ColorDocument({
@@ -215,7 +252,7 @@ export class CurrentUserUtils {
         return Docs.Create.ButtonDocument({
             _width: 35, _height: 25, title: "Tools", fontSize: 10, targetContainer: sidebarContainer,
             letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
-            sourcePanel: Docs.Create.StackingDocument([dragCreators, color], {
+            sourcePanel: Docs.Create.StackingDocument([doc.allCreators as Doc, color], {
                 _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true
             }),
             onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"),
@@ -228,6 +265,9 @@ export class CurrentUserUtils {
         doc.workspaces = Docs.Create.TreeDocument([], {
             title: "WORKSPACES", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true,
         });
+        const newWorkspace = ScriptField.MakeScript(`createNewWorkspace()`);
+        (doc.workspaces as Doc).contextMenuScripts = new List<ScriptField>([newWorkspace!]);
+        (doc.workspaces as Doc).contextMenuLabels = new List<string>(["Create New Workspace"]);
 
         doc.documents = Docs.Create.TreeDocument([], {
             title: "DOCUMENTS", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true,
@@ -237,11 +277,14 @@ export class CurrentUserUtils {
         doc.recentlyClosed = Docs.Create.TreeDocument([], {
             title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true,
         });
+        const clearAll = ScriptField.MakeScript(`self.data = new List([])`);
+        (doc.recentlyClosed as Doc).contextMenuScripts = new List<ScriptField>([clearAll!]);
+        (doc.recentlyClosed as Doc).contextMenuLabels = new List<string>(["Clear All"]);
 
         return Docs.Create.ButtonDocument({
             _width: 50, _height: 25, title: "Library", fontSize: 10,
             letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
-            sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, Docs.Prototypes.MainLinkDocument(), doc, doc.recentlyClosed as Doc], {
+            sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, doc.recentlyClosed as Doc, doc], {
                 title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "place", lockedPosition: true, boxShadow: "0 0", dontRegisterChildren: true
             }),
             targetContainer: sidebarContainer,
@@ -279,54 +322,28 @@ export class CurrentUserUtils {
         }));
     }
 
-    /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window
-    static setupExpandingButtons(doc: Doc) {
-        const queryTemplate = Docs.Create.MulticolumnDocument(
-            [
-                Docs.Create.QueryDocument({ title: "query", _height: 200, forceActive: true }),
-                Docs.Create.FreeformDocument([], { title: "data", _height: 100, _LODdisable: true, forceActive: true })
-            ],
-            { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true });
-        queryTemplate.isTemplateDoc = makeTemplate(queryTemplate);
-        const slideTemplate = Docs.Create.MultirowDocument(
-            [
-                Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, forceActive: true }),
-                Docs.Create.TextDocument("", { title: "text", _height: 100, forceActive: true })
-            ],
-            { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true });
-        slideTemplate.isTemplateDoc = makeTemplate(slideTemplate);
-        const descriptionTemplate = Docs.Create.TextDocument("", { title: "text", _height: 100, _showTitle: "title" });
-        Doc.GetProto(descriptionTemplate).layout = FormattedTextBox.LayoutString("description");
-        descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView");
+    static blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, {
+        ...opts,
+        _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", forceActive: true,
+        dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
+        backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true
+    })) as any as Doc;
 
-        const ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({
-            ...opts,
-            dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100
-        })) as any as Doc;
-        const blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, {
-            ...opts,
-            _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", forceActive: true,
-            dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
-            backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true
-        })) as any as Doc;
+    static ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({
+        ...opts,
+        dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100
+    })) as any as Doc;
 
-        doc.penBtn = ficon({
+    /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window
+    static setupExpandingButtons(doc: Doc) {
+        doc.penBtn = CurrentUserUtils.ficon({
             onClick: ScriptField.MakeScript("activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)"),
-            title: "ink mode", icon: "pen-nib", ischecked: ComputedField.MakeFunction(`sameDocs(this.activePen.pen,  this)`), activePen: doc
+            author: "systemTemplates", title: "ink mode", icon: "pen-nib", ischecked: ComputedField.MakeFunction(`sameDocs(this.activePen.pen,  this)`), activePen: doc
         })
-        doc.undoBtn = ficon({ onClick: ScriptField.MakeScript("undo()"), title: "undo button", icon: "undo-alt" });
-        doc.redoBtn = ficon({ onClick: ScriptField.MakeScript("redo()"), title: "redo button", icon: "redo-alt" });
-        doc.slidesBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "presentation slide", icon: "sticky-note" });
-        doc.descriptionBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: descriptionTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "description view", icon: "sticky-note" });
-        doc.queryBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: queryTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "query view", icon: "sticky-note" });
-        doc.templateButtons = blist({ title: "template buttons", ignoreClick: true }, [doc.slidesBtn as Doc, doc.descriptionBtn as Doc, doc.queryBtn as Doc]);
-        doc.expandingButtons = blist({ title: "expanding buttons", ignoreClick: true }, [doc.undoBtn as Doc, doc.redoBtn as Doc, doc.penBtn as Doc, doc.templateButtons as Doc]);
-        doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([doc.noteTypes as Doc, doc.templateButtons as Doc, doc.clickFuncs as Doc], {
-            title: "template layouts", _xPadding: 0,
-            dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name })
-        }));
+        doc.undoBtn = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), title: "undo button", icon: "undo-alt" });
+        doc.redoBtn = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), title: "redo button", icon: "redo-alt" });
+        doc.expandingButtons = CurrentUserUtils.blist({ title: "expanding buttons", ignoreClick: true }, [doc.undoBtn as Doc, doc.redoBtn as Doc, doc.penBtn as Doc]);
     }
-
     // sets up the default set of documents to be shown in the Overlay layer
     static setupOverlays(doc: Doc) {
         doc.overlays = new PrefetchProxy(Docs.Create.FreeformDocument([], { title: "Overlays", backgroundColor: "#aca3a6" }));
@@ -356,14 +373,15 @@ export class CurrentUserUtils {
     static updateUserDocument(doc: Doc) {
         doc.title = Doc.CurrentUserEmail;
         new InkingControl();
-        (doc.iconTypes === undefined) && CurrentUserUtils.setupDefaultIconTypes(doc);
-        (doc.noteTypes === undefined) && CurrentUserUtils.setupDefaultDocTemplates(doc);
         (doc.childClickFuncs === undefined) && CurrentUserUtils.setupChildClicks(doc);
+        (doc.iconTypes === undefined) && CurrentUserUtils.setupDefaultIconTypes(doc);
+        (doc.templateDocs === undefined) && CurrentUserUtils.setupDefaultDocTemplates(doc);
         (doc.optionalRightCollection === undefined) && CurrentUserUtils.setupMobileUploads(doc);
         (doc.overlays === undefined) && CurrentUserUtils.setupOverlays(doc);
         (doc.expandingButtons === undefined) && CurrentUserUtils.setupExpandingButtons(doc);
         (doc.curPresentation === undefined) && CurrentUserUtils.setupDefaultPresentation(doc);
         (doc.sidebarButtons === undefined) && CurrentUserUtils.setupSidebarButtons(doc);
+        doc.linkDb = Docs.Prototypes.MainLinkDocument();
 
         // this is equivalent to using PrefetchProxies to make sure all the childClickFuncs have been retrieved.
         PromiseValue(Cast(doc.childClickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast));
@@ -375,9 +393,9 @@ export class CurrentUserUtils {
         PromiseValue(Cast(doc.childClickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast));
         PromiseValue(Cast(doc.sidebarButtons, Doc)).then(stackingDoc => {
             stackingDoc && PromiseValue(Cast(stackingDoc.data, listSpec(Doc))).then(sidebarButtons => {
-                sidebarButtons && sidebarButtons.map((sidebarBtn, i) => {
-                    sidebarBtn && PromiseValue(Cast(sidebarBtn, Doc)).then(async btn => {
-                        btn && btn.sourcePanel && btn.targetContainer && i === 1 && (btn.onClick as ScriptField).script.run({ this: btn });
+                sidebarButtons?.map((sidebarBtn, i) => {
+                    sidebarBtn && PromiseValue(Cast(sidebarBtn, Doc)).then(async btn => { // choose which item to display first in sidebar panel (i === 0,1, or 2)
+                        btn?.sourcePanel && btn.targetContainer && i === 2 && (btn.onClick as ScriptField).script.run({ this: btn });
                     });
                 });
             });
@@ -427,3 +445,4 @@ export class CurrentUserUtils {
 
 Scripting.addGlobal(function setupMobileInkingDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileInkingDoc(userDoc); });
 Scripting.addGlobal(function setupMobileUploadDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileUploadDoc(userDoc); });
+Scripting.addGlobal(function createNewWorkspace() { return MainView.Instance.createNewWorkspace(); });
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 72f614f023a4bac6a2f0b63a1b1a16e6f4545c7a Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 23 Apr 2020 00:53:08 -0400
Subject: fixed browser back after link navigation. simplified menus more.
 fixed jitter mode to be seeded. fixed menu gear for  collections. .

---
 src/client/util/History.ts                         |  6 +++-
 src/client/util/ProsemirrorExampleTransfer.ts      |  4 +--
 src/client/views/DocumentDecorations.tsx           |  6 +++-
 .../views/collections/CollectionDockingView.tsx    |  6 +++-
 .../views/collections/CollectionStackingView.tsx   |  2 +-
 .../views/collections/CollectionTimeView.tsx       |  2 +-
 .../views/collections/CollectionTreeView.tsx       |  2 +-
 src/client/views/collections/CollectionView.tsx    |  4 +--
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 21 +++++------
 src/client/views/nodes/AudioBox.tsx                |  2 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  9 +++--
 src/client/views/nodes/DocumentBox.tsx             |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  2 +-
 src/client/views/nodes/FormattedTextBox.tsx        | 41 ++++++++++++++++++++--
 src/client/views/nodes/KeyValueBox.tsx             | 23 ++++++++----
 src/client/views/nodes/LinkAnchorBox.tsx           |  2 +-
 src/client/views/nodes/PDFBox.tsx                  |  2 +-
 src/client/views/nodes/ScreenshotBox.tsx           |  2 +-
 src/client/views/nodes/SliderBox.tsx               |  2 +-
 src/client/views/nodes/VideoBox.tsx                |  2 +-
 20 files changed, 103 insertions(+), 39 deletions(-)

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

diff --git a/src/client/util/History.ts b/src/client/util/History.ts
index 545e8acb4..2c53d7e52 100644
--- a/src/client/util/History.ts
+++ b/src/client/util/History.ts
@@ -40,8 +40,12 @@ export namespace HistoryUtil {
         // }
     }
 
+    let _lastStatePush = 0;
     export function pushState(state: ParsedUrl) {
-        history.pushState(state, "", createUrl(state));
+        if (Date.now() - _lastStatePush > 1000) {
+            history.pushState(state, "", createUrl(state));
+        }
+        _lastStatePush = Date.now();
     }
 
     export function replaceState(state: ParsedUrl) {
diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts
index 42247f177..680f48f70 100644
--- a/src/client/util/ProsemirrorExampleTransfer.ts
+++ b/src/client/util/ProsemirrorExampleTransfer.ts
@@ -154,7 +154,7 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, props: any
         const originalDoc = layoutDoc.rootDocument || layoutDoc;
         if (originalDoc instanceof Doc) {
             const newDoc = Docs.Create.TextDocument("", {
-                title: "", layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine),
+                layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine),
                 x: NumCast(originalDoc.x), y: NumCast(originalDoc.y) + NumCast(originalDoc._height) + 10, _width: NumCast(layoutDoc._width), _height: NumCast(layoutDoc._height)
             });
             FormattedTextBox.SelectOnLoad = newDoc[Id];
@@ -172,7 +172,7 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, props: any
         const originalDoc = layoutDoc.rootDocument || layoutDoc;
         if (force || props.Document._singleLine) {
             const newDoc = Docs.Create.TextDocument("", {
-                title: "", layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine),
+                layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine),
                 x: NumCast(originalDoc.x) + NumCast(originalDoc._width) + 10, y: NumCast(originalDoc.y), _width: NumCast(layoutDoc._width), _height: NumCast(layoutDoc._height)
             });
             FormattedTextBox.SelectOnLoad = newDoc[Id];
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 43c7751fa..6e699bc68 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -134,7 +134,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     @action onSettingsClick = (e: PointerEvent): void => {
         if (e.button === 0 && !e.altKey && !e.ctrlKey) {
             let child = SelectionManager.SelectedDocuments()[0].ContentDiv!.children[0];
-            while (child.children.length) child = child.children[0];
+            while (child.children.length) {
+                const next = Array.from(child.children).find(c => !c.className.includes("collectionViewChrome"));
+                if (next) child = next;
+                else break;
+            }
             simulateMouseClick(child, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
         }
     }
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 5e77bc0bb..0d859c3f1 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -29,6 +29,7 @@ import "./CollectionDockingView.scss";
 import { SubCollectionViewProps } from "./CollectionSubView";
 import { DockingViewButtonSelector } from './ParentDocumentSelector';
 import React = require("react");
+import { CollectionViewType } from './CollectionView';
 library.add(faFile);
 const _global = (window /* browser */ || global /* node */) as any;
 
@@ -93,6 +94,9 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
     @undoBatch
     @action
     public OpenFullScreen(docView: DocumentView, libraryPath?: Doc[]) {
+        if (docView.props.Document._viewType === CollectionViewType.Docking && docView.props.Document.layoutKey === "layout") {
+            return MainView.Instance.openWorkspace(docView.props.Document);
+        }
         const document = Doc.MakeAlias(docView.props.Document);
         const newItemStackConfig = {
             type: 'stack',
@@ -771,7 +775,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
 
     addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => {
         SelectionManager.DeselectAll();
-        if (doc.dockingConfig) {
+        if (doc._viewType === CollectionViewType.Docking && doc.layoutKey === "layout") {
             return MainView.Instance.openWorkspace(doc);
         } else if (location === "onRight") {
             return CollectionDockingView.AddRightSplit(doc, libraryPath);
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index b15649d83..24a3119cc 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -397,7 +397,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         if (!e.isPropagationStopped()) {
             const subItems: ContextMenuProps[] = [];
             subItems.push({ description: `${this.props.Document.fillColumn ? "Variable Size" : "Autosize"} Column`, event: () => this.props.Document.fillColumn = !this.props.Document.fillColumn, icon: "plus" });
-            ContextMenu.Instance.addItem({ description: "Stacking Options ...", subitems: subItems, icon: "eye" });
+            ContextMenu.Instance.addItem({ description: "Options...", subitems: subItems, icon: "eye" });
         }
     }
 
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 742a818bc..06ebf6d2d 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -102,7 +102,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
         layoutItems.push({ description: "Auto Time/Pivot layout", event: () => { doc._forceRenderEngine = undefined; }, icon: "compress-arrows-alt" });
         layoutItems.push({ description: "Sync with presentation", event: () => CollectionTimeView.SyncTimelineToPresentation(doc), icon: "compress-arrows-alt" });
 
-        ContextMenu.Instance.addItem({ description: "Pivot/Time Options ...", subitems: layoutItems, icon: "eye" });
+        ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" });
     }
     @computed get _allFacets() {
         const facets = new Set<string>();
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index f589c2c76..a052d045c 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -711,7 +711,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
             layoutItems.push({ description: (this.props.Document.treeViewPreventOpen ? "Persist" : "Abandon") + "Treeview State", event: () => this.props.Document.treeViewPreventOpen = !this.props.Document.treeViewPreventOpen, icon: "paint-brush" });
             layoutItems.push({ description: (this.props.Document.treeViewHideHeaderFields ? "Show" : "Hide") + " Header Fields", event: () => this.props.Document.treeViewHideHeaderFields = !this.props.Document.treeViewHideHeaderFields, icon: "paint-brush" });
             layoutItems.push({ description: (this.props.Document.treeViewHideTitle ? "Show" : "Hide") + " Title", event: () => this.props.Document.treeViewHideTitle = !this.props.Document.treeViewHideTitle, icon: "paint-brush" });
-            ContextMenu.Instance.addItem({ description: "Treeview Options ...", subitems: layoutItems, icon: "eye" });
+            ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" });
         }
         ContextMenu.Instance.addItem({
             description: "Buxton Layout", icon: "eye", event: () => {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index ade54f2c9..4f1242c33 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -229,7 +229,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
                 return newRendition;
             }, false);
 
-            const existing = ContextMenu.Instance.findByDescription("Layout...");
+            const existing = ContextMenu.Instance.findByDescription("Options...");
             const layoutItems = existing && "subitems" in existing ? existing.subitems : [];
             layoutItems.push({ description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" });
             if (this.props.Document.childLayout instanceof Doc) {
@@ -240,7 +240,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
             }
             layoutItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" });
 
-            !existing && ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "hand-point-right" });
+            !existing && ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "hand-point-right" });
 
             const existingOnClick = ContextMenu.Instance.findByDescription("OnClick...");
             const onClicks = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 3b5101a4d..55e55e56c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1048,16 +1048,17 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
 
     onContextMenu = (e: React.MouseEvent) => {
         if (this.props.children && this.props.annotationsKey) return;
-        const layoutItems: ContextMenuProps[] = [];
-
-        layoutItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" });
-        layoutItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" });
-        layoutItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" });
-        layoutItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" });
-        layoutItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" });
+        const options = ContextMenu.Instance.findByDescription("Options...");
+        const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : [];
+
+        optionItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" });
+        optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" });
+        optionItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" });
+        optionItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" });
+        optionItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" });
         // layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" });
-        layoutItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = 10), icon: "paint-brush" });
-        layoutItems.push({
+        optionItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = 10), icon: "paint-brush" });
+        optionItems.push({
             description: "Import document", icon: "upload", event: ({ x, y }) => {
                 const input = document.createElement("input");
                 input.type = "file";
@@ -1085,7 +1086,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             }
         });
 
-        ContextMenu.Instance.addItem({ description: "Freeform Options ...", subitems: layoutItems, icon: "eye" });
+        ContextMenu.Instance.addItem({ description: "Options...", subitems: optionItems, icon: "eye" });
     }
 
     private childViews = () => {
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 8f40ea2be..6ff6d1b42 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -162,7 +162,7 @@ export class AudioBox extends ViewBoxBaseComponent<FieldViewProps, AudioDocument
         const funcs: ContextMenuProps[] = [];
         funcs.push({ description: (this.layoutDoc.playOnSelect ? "Don't play" : "Play") + " when document selected", event: () => this.layoutDoc.playOnSelect = !this.layoutDoc.playOnSelect, icon: "expand-arrows-alt" });
 
-        ContextMenu.Instance.addItem({ description: "Audio Funcs...", subitems: funcs, icon: "asterisk" });
+        ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
     }
 
     stopRecording = action(() => {
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 3a7e005ac..615b05e43 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -1,4 +1,3 @@
-import anime from "animejs";
 import { computed, IReactionDisposer, observable, reaction, trace } from "mobx";
 import { observer } from "mobx-react";
 import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc";
@@ -29,8 +28,14 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
 @observer
 export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeFormDocumentViewProps, PositionDocument>(PositionDocument) {
     @observable _animPos: number[] | undefined = undefined;
+    random(min: number, max: number) { // min should not be equal to max
+        const mseed = Math.abs(this.X * this.Y);
+        const seed = (mseed * 9301 + 49297) % 233280;
+        var rnd = seed / 233280;
+        return min + rnd * (max - min);
+    }
     get displayName() { return "CollectionFreeFormDocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive
-    get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${anime.random(-1, 1) * this.props.jitterRotation}deg)`; }
+    get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${this.random(-1, 1) * this.props.jitterRotation}deg)`; }
     get X() { return this.renderScriptDim ? this.renderScriptDim.x : this.props.x !== undefined ? this.props.x : this.dataProvider ? this.dataProvider.x : (this.Document.x || 0); }
     get Y() { return this.renderScriptDim ? this.renderScriptDim.y : this.props.y !== undefined ? this.props.y : this.dataProvider ? this.dataProvider.y : (this.Document.y || 0); }
     get ZInd() { return this.dataProvider ? this.dataProvider.zIndex : (this.Document.zIndex || 0); }
diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx
index ac562f19a..7583aa070 100644
--- a/src/client/views/nodes/DocumentBox.tsx
+++ b/src/client/views/nodes/DocumentBox.tsx
@@ -45,7 +45,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
         funcs.push({ description: (this.props.Document.excludeCollections ? "Include" : "Exclude") + " Collections", event: () => Doc.GetProto(this.props.Document).excludeCollections = !this.props.Document.excludeCollections, icon: "expand-arrows-alt" });
         funcs.push({ description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" });
 
-        ContextMenu.Instance.addItem({ description: "DocumentBox Funcs...", subitems: funcs, icon: "asterisk" });
+        ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
     }
     @computed get contentDoc() {
         return (this.props.Document.isTemplateDoc || this.props.Document.isTemplateForField ? this.props.Document : Doc.GetProto(this.props.Document));
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index a19ba6506..cab7b965a 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -741,7 +741,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const existingOnClick = cm.findByDescription("OnClick...");
         const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
         onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" });
-        onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(this, "${this.props.Document.layoutKey}")`), icon: "window-restore" });
+        onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.props.Document.layoutKey}")`), icon: "window-restore" });
         onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" });
         onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: this.toggleFollowInPlace, icon: "concierge-bell" });
         onClicks.push({ description: this.Document.isLinkButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.toggleLinkButtonBehavior, icon: "concierge-bell" });
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 2c89d53d8..1329f7dcf 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -13,7 +13,7 @@ import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from "
 import { ReplaceStep } from 'prosemirror-transform';
 import { EditorView } from "prosemirror-view";
 import { DateField } from '../../../new_fields/DateField';
-import { DataSym, Doc, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc";
+import { DataSym, Doc, DocListCastAsync, Field, HeightSym, Opt, WidthSym, DocListCast } from "../../../new_fields/Doc";
 import { documentSchema } from '../../../new_fields/documentSchemas';
 import { Id } from '../../../new_fields/FieldSymbols';
 import { InkTool } from '../../../new_fields/InkField';
@@ -48,6 +48,7 @@ import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './Format
 import React = require("react");
 import { PrefetchProxy } from '../../../new_fields/Proxy';
 import { makeTemplate } from '../../util/DropConverter';
+import { DocumentView } from './DocumentView';
 
 library.add(faEdit);
 library.add(faSmile, faTextHeight, faUpload);
@@ -396,6 +397,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         return Cast(Doc.UserDoc().defaultTextLayout, Doc, null) || StrCast(Doc.UserDoc().defaultTextLayout, null);
     }
     specificContextMenu = (e: React.MouseEvent): void => {
+        const cm = ContextMenu.Instance;
+
         const funcs: ContextMenuProps[] = [];
         this.props.Document.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.props.Document), icon: "eye" });
         funcs.push({ description: "Reset Default Layout", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" });
@@ -407,10 +410,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         });
         funcs.push({ description: "Toggle Single Line", event: () => this.props.Document._singleLine = !this.props.Document._singleLine, icon: "expand-arrows-alt" });
         funcs.push({ description: "Toggle Sidebar", event: () => this.props.Document._showSidebar = !this.props.Document._showSidebar, icon: "expand-arrows-alt" });
-        funcs.push({ description: "Toggle Audio", event: () => this.props.Document._showAudio = !this.props.Document._showAudio, icon: "expand-arrows-alt" });
+        funcs.push({ description: "Toggle Dictation Icon", event: () => this.props.Document._showAudio = !this.props.Document._showAudio, icon: "expand-arrows-alt" });
         funcs.push({ description: "Toggle Menubar", event: () => this.toggleMenubar(), icon: "expand-arrows-alt" });
+
+        const highlighting: ContextMenuProps[] = [];
         ["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option =>
-            funcs.push({
+            highlighting.push({
                 description: (FormattedTextBox._highlights.indexOf(option) === -1 ? "Highlight " : "Unhighlight ") + option, event: () => {
                     e.stopPropagation();
                     if (FormattedTextBox._highlights.indexOf(option) === -1) {
@@ -421,8 +426,38 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     this.updateHighlights();
                 }, icon: "expand-arrows-alt"
             }));
+        funcs.push({ description: "highlighting...", subitems: highlighting, icon: "hand-point-right" });
 
         ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
+
+        const change = cm.findByDescription("Change Perspective...");
+        const changeItems: ContextMenuProps[] = change && "subitems" in change ? change.subitems : [];
+
+        const noteTypesDoc = Cast(Doc.UserDoc().noteTypes, Doc, null);
+        const noteTypes = DocListCast(noteTypesDoc?.data);
+        noteTypes.forEach(note => {
+            changeItems.push({
+                description: StrCast(note.title), event: () => {
+                    Doc.setNativeView(this.props.Document);
+                    DocumentView.makeCustomViewClicked(this.rootDoc, Docs.Create.TreeDocument, StrCast(note.title), note);
+                }, icon: "eye"
+            })
+        });
+        changeItems.push({ description: "FreeForm", event: () => DocumentView.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), icon: "eye" })
+        !change && cm.addItem({ description: "Change Perspective...", subitems: changeItems, icon: "external-link-alt" });
+
+        const open = cm.findByDescription("Open New Perspective...");
+        const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : [];
+
+        openItems.push({
+            description: "FreeForm", event: () => {
+                const alias = Doc.MakeAlias(this.rootDoc);
+                DocumentView.makeCustomViewClicked(alias, Docs.Create.FreeformDocument, "freeform");
+                this.props.addDocTab(alias, "onRight");
+            }, icon: "eye"
+        })
+        !open && cm.addItem({ description: "Open New Perspective...", subitems: openItems, icon: "external-link-alt" });
+
     }
 
     recordDictation = () => {
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 7aad6f90e..2970674a2 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -16,6 +16,8 @@ import { FieldView, FieldViewProps } from './FieldView';
 import "./KeyValueBox.scss";
 import { KeyValuePair } from "./KeyValuePair";
 import React = require("react");
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
 
 export type KVPScript = {
     script: CompiledScript;
@@ -34,11 +36,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
     @observable private _keyInput: string = "";
     @observable private _valueInput: string = "";
     @computed get splitPercentage() { return NumCast(this.props.Document.schemaSplitPercentage, 50); }
-    get fieldDocToLayout() { return this.props.fieldKey ? FieldValue(Cast(this.props.Document[this.props.fieldKey], Doc)) : this.props.Document; }
-
-    constructor(props: FieldViewProps) {
-        super(props);
-    }
+    get fieldDocToLayout() { return this.props.fieldKey ? Cast(this.props.Document[this.props.fieldKey], Doc, null) : this.props.Document; }
 
     @action
     onEnterKey = (e: React.KeyboardEvent): void => {
@@ -234,13 +232,26 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
         return new Doc;
     }
 
+    specificContextMenu = (e: React.MouseEvent): void => {
+        const cm = ContextMenu.Instance;
+        const open = cm.findByDescription("Change Perspective...");
+        const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : [];
+        openItems.push({
+            description: "Default Perspective", event: () => {
+                this.props.addDocTab(this.fieldDocToLayout, "inTab");
+                this.props.addDocTab(this.props.Document, "close");
+            }, icon: "image"
+        });
+        !open && cm.addItem({ description: "Change Perspective...", subitems: openItems, icon: "external-link-alt" });
+    }
+
     render() {
         const dividerDragger = this.splitPercentage === 0 ? (null) :
             <div className="keyValueBox-dividerDragger" style={{ transform: `translate(calc(${100 - this.splitPercentage}% - 5px), 0px)` }}>
                 <div className="keyValueBox-dividerDraggerThumb" onPointerDown={this.onDividerDown} />
             </div>;
 
-        return (<div className="keyValueBox-cont" onWheel={this.onPointerWheel} ref={this._mainCont}>
+        return (<div className="keyValueBox-cont" onWheel={this.onPointerWheel} onContextMenu={this.specificContextMenu} ref={this._mainCont}>
             <table className="keyValueBox-table">
                 <tbody className="keyValueBox-tbody">
                     <tr className="keyValueBox-header">
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index 8e3c15908..eb647d0e4 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -109,7 +109,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch
         funcs.push({ description: "Open Link Editor", event: () => this.openLinkEditor(e), icon: "eye" });
         funcs.push({ description: "Toggle Always Show Link", event: () => this.props.Document.linkDisplay = !this.props.Document.linkDisplay, icon: "eye" });
 
-        ContextMenu.Instance.addItem({ description: "Link Funcs...", subitems: funcs, icon: "asterisk" });
+        ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
     }
 
     render() {
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 6db36e43c..3712c648e 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -210,7 +210,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
         pdfUrl && funcs.push({ description: "Copy path", event: () => Utils.CopyText(pdfUrl.url.pathname), icon: "expand-arrows-alt" });
         funcs.push({ description: "Toggle Fit Width " + (this.Document._fitWidth ? "Off" : "On"), event: () => this.Document._fitWidth = !this.Document._fitWidth, icon: "expand-arrows-alt" });
 
-        ContextMenu.Instance.addItem({ description: "Pdf Funcs...", subitems: funcs, icon: "asterisk" });
+        ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
     }
 
     @computed get contentScaling() { return this.props.ContentScaling(); }
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 11b24b059..125690dc7 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -120,7 +120,7 @@ export class ScreenshotBox extends ViewBoxBaseComponent<FieldViewProps, Screensh
                     this._videoRef!.srcObject = !this._screenCapture ? undefined : await (navigator.mediaDevices as any).getDisplayMedia({ video: true });
                 }), icon: "expand-arrows-alt"
             });
-            ContextMenu.Instance.addItem({ description: "Screenshot Funcs...", subitems: subitems, icon: "video" });
+            ContextMenu.Instance.addItem({ description: "Options...", subitems: subitems, icon: "video" });
         }
     }
 
diff --git a/src/client/views/nodes/SliderBox.tsx b/src/client/views/nodes/SliderBox.tsx
index 746ea0b64..b2d451ea8 100644
--- a/src/client/views/nodes/SliderBox.tsx
+++ b/src/client/views/nodes/SliderBox.tsx
@@ -40,7 +40,7 @@ export class SliderBox extends ViewBoxBaseComponent<FieldViewProps, SliderDocume
     specificContextMenu = (e: React.MouseEvent): void => {
         const funcs: ContextMenuProps[] = [];
         funcs.push({ description: "Edit Thumb Change Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Thumb Change ...", this.props.Document, "onThumbChange", obj.x, obj.y) });
-        ContextMenu.Instance.addItem({ description: "Slider Funcs...", subitems: funcs, icon: "asterisk" });
+        ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
     }
     onChange = (values: readonly number[]) => runInAction(() => {
         this.dataDoc[this.minThumbKey] = values[0];
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 588068334..613929bca 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -209,7 +209,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
                     this._videoRef!.srcObject = !this._screenCapture ? undefined : await (navigator.mediaDevices as any).getDisplayMedia({ video: true });
                 }), icon: "expand-arrows-alt"
             });
-            ContextMenu.Instance.addItem({ description: "Video Funcs...", subitems: subitems, icon: "video" });
+            ContextMenu.Instance.addItem({ description: "Options...", subitems: subitems, icon: "video" });
         }
     }
 
-- 
cgit v1.2.3-70-g09d2


From 492e203d95ce9b5aa5e2b2bd7feaf542415a3579 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 26 Apr 2020 21:22:51 -0400
Subject: fixed multi/col/row views to work with templates.  fixed context menu
 subitems to appear on screen. fixed tree view display of text nodes.

---
 src/client/views/ContextMenu.scss                  | 47 +++++++++++++++++-----
 src/client/views/ContextMenuItem.tsx               | 16 +++++---
 .../views/collections/CollectionStackingView.tsx   |  4 +-
 .../views/collections/CollectionTreeView.tsx       | 20 +++++----
 .../CollectionMulticolumnView.tsx                  | 31 +++++++++-----
 .../CollectionMultirowView.tsx                     | 31 +++++++++-----
 src/client/views/nodes/RadialMenu.scss             | 13 ------
 src/client/views/nodes/RadialMenu.tsx              |  9 ++---
 .../authentication/models/current_user_utils.ts    | 28 ++++++++++++-
 9 files changed, 133 insertions(+), 66 deletions(-)

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

diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss
index 8f112de0c..30938688d 100644
--- a/src/client/views/ContextMenu.scss
+++ b/src/client/views/ContextMenu.scss
@@ -61,6 +61,42 @@
     letter-spacing: 2px;
     text-transform: uppercase;
     padding-right: 30px;
+
+    .icon-background {
+        pointer-events: all;
+        background-color: transparent;
+        width: 35px;
+        text-align: center;
+        font-size: 20px;
+        margin-left: 5px;
+        margin-top: 5px;
+        margin-bottom: 5px;
+        height: 20px;
+    }
+}
+.contextMenu-description {
+    // width: 11vw; //10vw
+    background: whitesmoke;
+    display: flex; //comment out to allow search icon to be inline with search text
+    justify-content: left;
+    -webkit-touch-callout: none;
+    -webkit-user-select: none;
+    -khtml-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+    transition: all .1s;
+    border-style: none;
+    // padding: 10px 0px 10px 0px;
+    white-space: nowrap;
+    font-size: 13px;
+    color: grey;
+    letter-spacing: 2px;
+    text-transform: uppercase;
+    padding-right: 30px;
+    margin-top: 5px;
+    height: 20px;
+    margin-bottom: 5px;
 }
 
 .contextMenu-item:hover {
@@ -121,15 +157,4 @@
     padding-left: 10px;
     border: solid black 1px;
     border-radius: 5px;
-}
-
-.icon-background {
-    pointer-events: all;
-    height:100%;
-    margin-top: 15px;
-    background-color: transparent;
-    width: 35px;
-    text-align: center;
-    font-size: 20px;
-    margin-left: 5px;
 }
\ No newline at end of file
diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index fef9e5f60..99840047f 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -51,7 +51,8 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
 
     currentTimeout?: any;
     static readonly timeout = 300;
-    onPointerEnter = () => {
+    _overPosY = 0;
+    onPointerEnter = (e: React.MouseEvent) => {
         if (this.currentTimeout) {
             clearTimeout(this.currentTimeout);
             this.currentTimeout = undefined;
@@ -59,6 +60,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
         if (this.overItem) {
             return;
         }
+        this._overPosY = e.clientY;
         this.currentTimeout = setTimeout(action(() => this.overItem = true), ContextMenuItem.timeout);
     }
 
@@ -88,18 +90,22 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
                 </div>
             );
         } else if ("subitems" in this.props) {
+            const where = !this.overItem ? "" : this._overPosY < window.innerHeight / 3 ? "flex-start" : this._overPosY > window.innerHeight * 2 / 3 ? "flex-end" : "center";
+            const marginTop = !this.overItem ? "" : this._overPosY < window.innerHeight / 3 ? "20px" : this._overPosY > window.innerHeight * 2 / 3 ? "-20px" : "";
             const submenu = !this.overItem ? (null) :
-                <div className="contextMenu-subMenu-cont" style={{ marginLeft: "25%", left: "0px" }}>
+                <div className="contextMenu-subMenu-cont" style={{ marginLeft: "25%", left: "0px", marginTop }}>
                     {this._items.map(prop => <ContextMenuItem {...prop} key={prop.description} closeMenu={this.props.closeMenu} />)}
                 </div>;
             return (
-                <div className={"contextMenu-item" + (this.props.selected ? " contextMenu-itemSelected" : "")} onMouseLeave={this.onPointerLeave} onMouseEnter={this.onPointerEnter}>
+                <div className={"contextMenu-item" + (this.props.selected ? " contextMenu-itemSelected" : "")} style={{ alignItems: where }}
+                    onMouseLeave={this.onPointerLeave} onMouseEnter={this.onPointerEnter}>
                     {this.props.icon ? (
-                        <span className="icon-background" onMouseEnter={this.onPointerLeave}>
+                        <span className="icon-background" onMouseEnter={this.onPointerLeave} style={{ alignItems: "center" }}>
                             <FontAwesomeIcon icon={this.props.icon} size="sm" />
                         </span>
                     ) : null}
-                    <div className="contextMenu-description" onMouseEnter={this.onPointerEnter} >
+                    <div className="contextMenu-description" onMouseEnter={this.onPointerEnter}
+                        style={{ alignItems: "center" }} >
                         {this.props.description}
                         <FontAwesomeIcon icon={faAngleRight} size="lg" style={{ position: "absolute", right: "10px" }} />
                     </div>
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 24a3119cc..799bc7f67 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -189,8 +189,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             active={this.props.active}
             whenActiveChanged={this.props.whenActiveChanged}
             addDocTab={this.addDocTab}
-            pinToPres={this.props.pinToPres}>
-        </ContentFittingDocumentView>;
+            pinToPres={this.props.pinToPres}
+        />;
     }
 
     getDocWidth(d?: Doc) {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 7f5dc98f1..218c5705d 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -348,7 +348,9 @@ class TreeView extends React.Component<TreeViewProps> {
             </div></ul>;
         } else {
             const layoutDoc = Doc.Layout(this.props.document);
-            return <div ref={this._dref} style={{ display: "inline-block", height: this.docHeight() }} key={this.props.document[Id] + this.props.document.title}>
+            const panelHeight = layoutDoc.type === DocumentType.RTF ? this.rtfHeight : this.docHeight;
+            const panelWidth = layoutDoc.type === DocumentType.RTF ? this.rtfWidth : this.docWidth;
+            return <div ref={this._dref} style={{ display: "inline-block", height: panelHeight() }} key={this.props.document[Id] + this.props.document.title}>
                 <ContentFittingDocumentView
                     Document={layoutDoc}
                     DataDocument={this.templateDataDoc}
@@ -360,8 +362,8 @@ class TreeView extends React.Component<TreeViewProps> {
                     FreezeDimensions={true}
                     NativeWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : undefined}
                     NativeHeight={layoutDoc.type === DocumentType.RTF ? this.rtfHeight : undefined}
-                    PanelWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : this.docWidth}
-                    PanelHeight={layoutDoc.type === DocumentType.RTF ? this.rtfHeight : this.docHeight}
+                    PanelWidth={panelWidth}
+                    PanelHeight={panelHeight}
                     getTransform={this.docTransform}
                     CollectionDoc={this.props.containingCollection}
                     CollectionView={undefined}
@@ -727,7 +729,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
                         }
                     });
                 });
-                const { TextDocument, ImageDocument, CarouselDocument } = Docs.Create;
+                const { TextDocument, ImageDocument, CarouselDocument, TreeDocument } = Docs.Create;
                 const { Document } = this.props;
                 const fallbackImg = "http://www.cs.brown.edu/~bcz/face.gif";
                 const detailedTemplate = `{ "doc": { "type": "doc", "content": [  { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "year" } } ] },  { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "company" } } ] }  ] }, "selection":{"type":"text","anchor":1,"head":1},"storedMarks":[] }`;
@@ -735,10 +737,12 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
                 const textDoc = TextDocument("", { title: "details", _autoHeight: true });
                 const detailView = Docs.Create.StackingDocument([
                     CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, backgroundColor: "#9b9b9b3F" }),
-                    // textDoc,
-                    TextDocument("", { title: "shortDescription", _autoHeight: true }),
-                    // TreeDocument([], { title: "narratives", _height: 75, treeViewHideTitle: true }),
-                    TextDocument("", { title: "longDescription", _height: 350 })
+                    TreeDocument([
+                        // textDoc,
+                        TextDocument("", { title: "shortDescription", _autoHeight: true }),
+                        // TreeDocument([], { title: "narratives", _height: 75, treeViewHideTitle: true }),
+                        TextDocument("", { title: "longDescription", _height: 350 })
+                    ], { title: "stuff", _height: 100 })
                 ], { _chromeStatus: "disabled", _width: 300, _height: 300, _autoHeight: true, title: "detailView" });
                 textDoc.data = new RichTextField(detailedTemplate, "year company");
                 detailView.isTemplateDoc = makeTemplate(detailView);
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 0e1cc2010..9d09ecc3b 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -5,7 +5,7 @@ import { Doc } from '../../../../new_fields/Doc';
 import { documentSchema } from '../../../../new_fields/documentSchemas';
 import { makeInterface } from '../../../../new_fields/Schema';
 import { BoolCast, NumCast, ScriptCast, StrCast, Cast } from '../../../../new_fields/Types';
-import { DragManager } from '../../../util/DragManager';
+import { DragManager, dropActionType } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
 import { ContentFittingDocumentView } from '../../nodes/ContentFittingDocumentView';
@@ -214,21 +214,32 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
     }
     getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) {
         return <ContentFittingDocumentView
-            {...this.props}
             Document={layout}
             DataDocument={layout.resolvedDataDoc as Doc}
-            NativeHeight={returnZero}
-            NativeWidth={returnZero}
-            addDocTab={this.addDocTab}
-            fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
-            FreezeDimensions={BoolCast(this.props.Document._freezeChildDimensions)}
             backgroundColor={this.props.backgroundColor}
-            CollectionDoc={this.props.Document}
+            LayoutDoc={this.props.childLayoutTemplate}
+            LibraryPath={this.props.LibraryPath}
+            FreezeDimensions={this.props.freezeChildDimensions}
+            renderDepth={this.props.renderDepth + 1}
             PanelWidth={width}
             PanelHeight={height}
-            getTransform={dxf}
+            NativeHeight={returnZero}
+            NativeWidth={returnZero}
+            fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
+            rootSelected={this.rootSelected}
+            dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             onClick={this.onChildClickHandler}
-            renderDepth={this.props.renderDepth + 1}
+            getTransform={dxf}
+            focus={this.props.focus}
+            CollectionDoc={this.props.CollectionView?.props.Document}
+            CollectionView={this.props.CollectionView}
+            addDocument={this.props.addDocument}
+            moveDocument={this.props.moveDocument}
+            removeDocument={this.props.removeDocument}
+            active={this.props.active}
+            whenActiveChanged={this.props.whenActiveChanged}
+            addDocTab={this.addDocTab}
+            pinToPres={this.props.pinToPres}
         />;
     }
     /**
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 1eb486c4f..af0cc3b5c 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -13,7 +13,7 @@ import { Transform } from '../../../util/Transform';
 import HeightLabel from './MultirowHeightLabel';
 import ResizeBar from './MultirowResizer';
 import { undoBatch } from '../../../util/UndoManager';
-import { DragManager } from '../../../util/DragManager';
+import { DragManager, dropActionType } from '../../../util/DragManager';
 import { List } from '../../../../new_fields/List';
 
 type MultirowDocument = makeInterface<[typeof documentSchema]>;
@@ -214,21 +214,32 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
     }
     getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) {
         return <ContentFittingDocumentView
-            {...this.props}
             Document={layout}
             DataDocument={layout.resolvedDataDoc as Doc}
-            NativeHeight={returnZero}
-            NativeWidth={returnZero}
-            addDocTab={this.addDocTab}
-            fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
-            FreezeDimensions={BoolCast(this.props.Document._freezeChildDimensions)}
             backgroundColor={this.props.backgroundColor}
-            CollectionDoc={this.props.Document}
+            LayoutDoc={this.props.childLayoutTemplate}
+            LibraryPath={this.props.LibraryPath}
+            FreezeDimensions={this.props.freezeChildDimensions}
+            renderDepth={this.props.renderDepth + 1}
             PanelWidth={width}
             PanelHeight={height}
-            getTransform={dxf}
+            NativeHeight={returnZero}
+            NativeWidth={returnZero}
+            fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
+            rootSelected={this.rootSelected}
+            dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             onClick={this.onChildClickHandler}
-            renderDepth={this.props.renderDepth + 1}
+            getTransform={dxf}
+            focus={this.props.focus}
+            CollectionDoc={this.props.CollectionView?.props.Document}
+            CollectionView={this.props.CollectionView}
+            addDocument={this.props.addDocument}
+            moveDocument={this.props.moveDocument}
+            removeDocument={this.props.removeDocument}
+            active={this.props.active}
+            whenActiveChanged={this.props.whenActiveChanged}
+            addDocTab={this.addDocTab}
+            pinToPres={this.props.pinToPres}
         />;
     }
     /**
diff --git a/src/client/views/nodes/RadialMenu.scss b/src/client/views/nodes/RadialMenu.scss
index ce0c263ef..daa620d12 100644
--- a/src/client/views/nodes/RadialMenu.scss
+++ b/src/client/views/nodes/RadialMenu.scss
@@ -67,17 +67,4 @@ s
     margin-left: 5px;
     text-align: left;
     display: inline; //need this?
-}
-
-
-
-.icon-background {
-    pointer-events: all;
-    height:100%;
-    margin-top: 15px;
-    background-color: transparent;
-    width: 35px;
-    text-align: center;
-    font-size: 20px;
-    margin-left: 5px;
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/RadialMenu.tsx b/src/client/views/nodes/RadialMenu.tsx
index 0ffed78de..ddfdb67b4 100644
--- a/src/client/views/nodes/RadialMenu.tsx
+++ b/src/client/views/nodes/RadialMenu.tsx
@@ -1,12 +1,9 @@
 import React = require("react");
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
-import { action, observable, computed, IReactionDisposer, reaction, runInAction } from "mobx";
-import { RadialMenuItem, RadialMenuProps } from "./RadialMenuItem";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import Measure from "react-measure";
-import "./RadialMenu.scss";
-import MobileInkOverlay from "../../../mobile/MobileInkOverlay";
 import MobileInterface from "../../../mobile/MobileInterface";
+import "./RadialMenu.scss";
+import { RadialMenuItem, RadialMenuProps } from "./RadialMenuItem";
 
 @observer
 export class RadialMenu extends React.Component {
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 25775edef..76aa51f63 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -82,8 +82,34 @@ export class CurrentUserUtils {
             });
         }
 
+        if (doc["template-button-detail"] === undefined) {
+            const { TextDocument, ImageDocument, CarouselDocument, TreeDocument } = Docs.Create;
+            const fallbackImg = "http://www.cs.brown.edu/~bcz/face.gif";
+            const detailedTemplate = `{ "doc": { "type": "doc", "content": [  { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "year" } } ] },  { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "company" } } ] }  ] }, "selection":{"type":"text","anchor":1,"head":1},"storedMarks":[] }`;
+
+            const textDoc = TextDocument("", { title: "details", _autoHeight: true });
+            const detailView = Docs.Create.MultirowDocument([
+                CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, backgroundColor: "#9b9b9b3F" }),
+                TreeDocument([
+                    // textDoc,
+                    TextDocument("", { title: "short description", _autoHeight: true }),
+                    // TreeDocument([], { title: "narratives", _height: 75, treeViewHideTitle: true }),
+                    TextDocument("", { title: "long description", _height: 350 })
+                ], { title: "stuff", _height: 100 })
+            ], { _chromeStatus: "disabled", _width: 300, _height: 300, _autoHeight: true, title: "detailView" });
+            textDoc.data = new RichTextField(detailedTemplate, "year company");
+            detailView.isTemplateDoc = makeTemplate(detailView);
+
+            doc["template-button-detail"] = CurrentUserUtils.ficon({
+                onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'),
+                dragFactory: new PrefetchProxy(detailView) as any as Doc,
+                removeDropProperties: new List<string>(["dropAction"]), title: "detail view", icon: "window-maximize"
+            });
+        }
+
         if (doc["template-buttons"] === undefined) {
-            doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument([doc["template-button-slides"] as Doc, doc["template-button-description"] as Doc, doc["template-button-query"] as Doc], {
+            doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument([doc["template-button-slides"] as Doc, doc["template-button-description"] as Doc,
+            doc["template-button-query"] as Doc, doc["template-button-detail"] as Doc], {
                 title: "Compound Item Creators", _xMargin: 0, _showTitle: "title",
                 _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled",
                 dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
-- 
cgit v1.2.3-70-g09d2


From 7f6bc06f72e070bd8b45eba8b4c0669ee398387b Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 27 Apr 2020 02:55:59 -0400
Subject: fixed fontsize inheritance.  fixed masonry view with a columnWidth of
 -1 to fit width.  cleaned up masonry and editableViews

---
 src/client/documents/Documents.ts                  |  3 +-
 src/client/util/RichTextRules.ts                   |  2 +-
 src/client/views/EditableView.tsx                  |  2 -
 .../collections/CollectionMasonryViewFieldRow.tsx  | 53 ++++++++--------------
 .../views/collections/CollectionStackingView.tsx   |  4 +-
 .../CollectionStackingViewFieldColumn.tsx          |  5 --
 src/client/views/nodes/DocumentView.tsx            |  4 +-
 src/client/views/nodes/FormattedTextBox.tsx        |  4 +-
 src/client/views/nodes/LabelBox.tsx                |  3 +-
 src/client/views/nodes/SliderBox.tsx               |  2 +-
 src/new_fields/documentSchemas.ts                  |  2 +
 11 files changed, 35 insertions(+), 49 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 5e0890e76..c64916897 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -110,7 +110,8 @@ export interface DocumentOptions {
     isBackground?: boolean;
     isLinkButton?: boolean;
     columnWidth?: number;
-    fontSize?: number;
+    _fontSize?: number;
+    _fontFamily?: string;
     curPage?: number;
     currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video)  value is in seconds
     displayTimecode?: number; // the time that a document should be displayed (e.g., time an annotation should be displayed on a video)
diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts
index 3746199ba..8b11be6fb 100644
--- a/src/client/util/RichTextRules.ts
+++ b/src/client/util/RichTextRules.ts
@@ -143,7 +143,7 @@ export class RichTextRules {
                     textDoc.inlineTextCount = numInlines + 1;
                     const inlineFieldKey = "inline" + numInlines; // which field on the text document this annotation will write to
                     const inlineLayoutKey = "layout_" + inlineFieldKey; // the field holding the layout string that will render the inline annotation
-                    const textDocInline = Docs.Create.TextDocument("", { layoutKey: inlineLayoutKey, _width: 75, _height: 35, annotationOn: textDoc, _autoHeight: true, fontSize: 9, title: "inline comment" });
+                    const textDocInline = Docs.Create.TextDocument("", { layoutKey: inlineLayoutKey, _width: 75, _height: 35, annotationOn: textDoc, _autoHeight: true, _fontSize: 9, title: "inline comment" });
                     textDocInline.title = inlineFieldKey; // give the annotation its own title
                     textDocInline.customTitle = true; // And make sure that it's 'custom' so that editing text doesn't change the title of the containing doc
                     textDocInline.isTemplateForField = inlineFieldKey; // this is needed in case the containing text doc is converted to a template at some point
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 2219966e5..c51173ad3 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -46,7 +46,6 @@ export interface EditableProps {
     menuCallback?: (x: number, y: number) => void;
     showMenuOnLoad?: boolean;
     HeadingObject?: SchemaHeaderField | undefined;
-    HeadingsHack?: number;
     toggle?: () => void;
     color?: string | undefined;
 }
@@ -60,7 +59,6 @@ export interface EditableProps {
 export class EditableView extends React.Component<EditableProps> {
     public static loadId = "";
     @observable _editing: boolean = false;
-    @observable _headingsHack: number = 1;
 
     constructor(props: EditableProps) {
         super(props);
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index b272151c1..42f0c4311 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -4,7 +4,6 @@ import { faPalette } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
-import Measure from "react-measure";
 import { Doc } from "../../../new_fields/Doc";
 import { PastelSchemaPalette, SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
 import { ScriptField } from "../../../new_fields/ScriptField";
@@ -46,7 +45,6 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     @observable private _background = "inherit";
     @observable private _createAliasSelected: boolean = false;
     @observable private _collapsed: boolean = false;
-    @observable private _headingsHack: number = 1;
     @observable private _heading = this.props.headingObject ? this.props.headingObject.heading : this.props.heading;
     @observable private _color = this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
 
@@ -55,7 +53,6 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     private _startDragPosition: { x: number, y: number } = { x: 0, y: 0 };
     private _contRef: React.RefObject<HTMLDivElement> = React.createRef();
     private _sensitivity: number = 16;
-    private _counter: number = 0;
     private _ele: any;
 
     createRowDropRef = (ele: HTMLDivElement | null) => {
@@ -167,7 +164,6 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     collapseSection = () => {
         this._createAliasSelected = false;
         if (this.props.headingObject) {
-            this._headingsHack++;
             this.props.headingObject.setCollapsed(!this.props.headingObject.collapsed);
             this.toggleVisibility();
         }
@@ -197,6 +193,10 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
         e.stopPropagation();
         e.preventDefault();
 
+        if (this.props.parent.props.Document._chromeStatus === "disabled") {
+            this.collapseSection();
+        }
+
         document.removeEventListener("pointermove", this.startDrag);
         document.removeEventListener("pointerup", this.pointerUp);
     }
@@ -209,7 +209,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
         const [dx, dy] = this.props.screenToLocalTransform().transformDirection(e.clientX, e.clientY);
         this._startDragPosition = { x: dx, y: dy };
 
-        if (this._createAliasSelected) {
+        if (this.props.parent.props.Document._chromeStatus === "disabled" || this._createAliasSelected) {
             document.removeEventListener("pointermove", this.startDrag);
             document.addEventListener("pointermove", this.startDrag);
             document.removeEventListener("pointerup", this.pointerUp);
@@ -261,12 +261,6 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
         </div>);
     }
 
-    handleResize = (size: any) => {
-        if (++this._counter !== 1) {
-            this.getTrueHeight();
-        }
-    }
-
     @computed get contentLayout() {
         const rows = Math.max(1, Math.min(this.props.docList.length, Math.floor((this.props.parent.props.PanelWidth() - 2 * this.props.parent.xMargin) / (this.props.parent.columnWidth + this.props.parent.gridGap))));
         const style = this.props.parent;
@@ -277,7 +271,6 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
             SetValue: this.addDocument,
             contents: "+ NEW",
             HeadingObject: this.props.headingObject,
-            HeadingsHack: this._headingsHack,
             toggle: this.toggleVisibility,
             color: this._color
         };
@@ -308,6 +301,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
 
     @computed get headingView() {
         const heading = this._heading;
+        const noChrome = this.props.parent.props.Document._chromeStatus === "disabled";
         const key = StrCast(this.props.parent.props.Document._pivotField);
         const evContents = heading ? heading : this.props.type && this.props.type === "number" ? "0" : `NO ${key.toUpperCase()} VALUE`;
         const headerEditableViewProps = {
@@ -316,7 +310,6 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
             contents: evContents,
             oneLine: true,
             HeadingObject: this.props.headingObject,
-            HeadingsHack: this._headingsHack,
             toggle: this.toggleVisibility,
             color: this._color
         };
@@ -326,12 +319,12 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
             </div> :
             !this.props.headingObject ? (null) :
                 <div className="collectionStackingView-sectionHeader" ref={this._headerRef} >
-                    <div className="collectionStackingView-sectionHeader-subCont" onPointerDown={this.headerDown}
+                    <div className="collectionStackingView-sectionHeader-subCont" onPointerDown={this.headerDown} onClick={noChrome ? undefined : this.collapseSection}
                         title={evContents === `NO ${key.toUpperCase()} VALUE` ?
                             `Documents that don't have a ${key} value will go here. This column cannot be removed.` : ""}
                         style={{ background: evContents !== `NO ${key.toUpperCase()} VALUE` ? this._color : "lightgrey" }}>
                         <EditableView {...headerEditableViewProps} />
-                        {evContents === `NO ${key.toUpperCase()} VALUE` ? (null) :
+                        {noChrome || evContents === `NO ${key.toUpperCase()} VALUE` ? (null) :
                             <div className="collectionStackingView-sectionColor">
                                 <Flyout anchorPoint={anchorPoints.CENTER_RIGHT} content={this.renderColorPicker()}>
                                     <button className="collectionStackingView-sectionColorButton">
@@ -340,10 +333,10 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
                                 </ Flyout >
                             </div>
                         }
-                        <button className="collectionStackingView-sectionDelete" onClick={this.collapseSection}>
+                        {noChrome ? (null) : <button className="collectionStackingView-sectionDelete" onClick={noChrome ? undefined : this.collapseSection}>
                             <FontAwesomeIcon icon={this._collapsed ? "chevron-down" : "chevron-up"} size="lg" />
-                        </button>
-                        {evContents === `NO  ${key.toUpperCase()} VALUE` ? (null) :
+                        </button>}
+                        {noChrome || evContents === `NO  ${key.toUpperCase()} VALUE` ? (null) :
                             <div className="collectionStackingView-sectionOptions">
                                 <Flyout anchorPoint={anchorPoints.TOP_RIGHT} content={this.renderMenu()}>
                                     <button className="collectionStackingView-sectionOptionButton">
@@ -359,20 +352,14 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
         const background = this._background; //to account for observables in Measure
         const contentlayout = this.contentLayout;
         const headingview = this.headingView;
-        return <Measure offset onResize={this.handleResize}>
-            {({ measureRef }) => {
-                return <div ref={measureRef}>
-                    <div className="collectionStackingView-masonrySection"
-                        style={{ width: this.props.parent.NodeWidth, background }}
-                        ref={this.createRowDropRef}
-                        onPointerEnter={this.pointerEnteredRow}
-                        onPointerLeave={this.pointerLeaveRow}
-                    >
-                        {headingview}
-                        {contentlayout}
-                    </div >
-                </div>;
-            }}
-        </Measure>;
+        return <div className="collectionStackingView-masonrySection"
+            style={{ width: this.props.parent.NodeWidth, background }}
+            ref={this.createRowDropRef}
+            onPointerEnter={this.pointerEnteredRow}
+            onPointerLeave={this.pointerLeaveRow}
+        >
+            {headingview}
+            {contentlayout}
+        </div >;
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 799bc7f67..e3720bf01 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -49,7 +49,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @computed get columnWidth() {
         TraceMobx();
         return Math.min(this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin,
-            this.isStackingView ? Number.MAX_VALUE : NumCast(this.props.Document.columnWidth, 250));
+            this.isStackingView ? Number.MAX_VALUE : this.props.Document.columnWidth === -1 ? this.props.PanelWidth() - 2 * this.xMargin : NumCast(this.props.Document.columnWidth, 250));
     }
     @computed get NodeWidth() { return this.props.PanelWidth() - this.gridGap; }
 
@@ -303,7 +303,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                     const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
                     this.observer = new _global.ResizeObserver(action((entries: any) => {
                         if (this.props.Document._autoHeight && ref && this.refList.length && !SelectionManager.GetIsDragging()) {
-                            Doc.Layout(doc)._height = Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", ""))));
+                            Doc.Layout(doc)._height = Math.min(1200, Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))));
                         }
                     }));
                     this.observer.observe(ref);
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 8992de9d1..323d7be25 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -156,7 +156,6 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
     @action
     collapseSection = () => {
         if (this.props.headingObject) {
-            this._headingsHack++;
             this.props.headingObject.setCollapsed(!this.props.headingObject.collapsed);
             this.toggleVisibility();
         }
@@ -225,8 +224,6 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
 
     private toggleVisibility = action(() => this.collapsed = !this.collapsed);
 
-    @observable _headingsHack: number = 1;
-
     menuCallback = (x: number, y: number) => {
         ContextMenu.Instance.clearItems();
         const layoutItems: ContextMenuProps[] = [];
@@ -300,7 +297,6 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
             contents: evContents,
             oneLine: true,
             HeadingObject: this.props.headingObject,
-            HeadingsHack: this._headingsHack,
             toggle: this.toggleVisibility,
             color: this._color
         };
@@ -309,7 +305,6 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
             SetValue: this.addDocument,
             contents: "+ NEW",
             HeadingObject: this.props.headingObject,
-            HeadingsHack: this._headingsHack,
             toggle: this.toggleVisibility,
             color: this._color
         };
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f8bf9bf64..4b5fadd93 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1144,7 +1144,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined,
                 boxShadow: this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined,
                 background: finalColor,
-                opacity: this.Document.opacity
+                opacity: this.Document.opacity,
+                fontFamily: StrCast(this.Document._fontFamily, "inherit"),
+                fontSize: Cast(this.Document._fontSize, "number", null)
             }}>
             {this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ? <>
                 {this.innards}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 567d4c440..7fc0cbb94 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1216,8 +1216,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     opacity: this.props.hideOnLeave ? (this._entered ? 1 : 0.1) : 1,
                     color: this.props.hideOnLeave ? "white" : "inherit",
                     pointerEvents: interactive ? "none" : undefined,
-                    fontSize: NumCast(this.layoutDoc.fontSize, 13),
-                    fontFamily: StrCast(this.layoutDoc.fontFamily, "Crimson Text"),
+                    fontSize: Cast(this.layoutDoc._fontSize, "number", null),
+                    fontFamily: StrCast(this.layoutDoc._fontFamily, "inherit"),
                 }}
                 onContextMenu={this.specificContextMenu}
                 onKeyDown={this.onKeyPress}
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 59c695f21..3cdec8acb 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -72,7 +72,8 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps, LabelDocument
                 <div className="labelBox-mainButton" style={{
                     background: StrCast(this.layoutDoc.backgroundColor),
                     color: StrCast(this.layoutDoc.color, "inherit"),
-                    fontSize: NumCast(this.layoutDoc.fontSize) || "inherit",
+                    fontSize: NumCast(this.layoutDoc._fontSize) || "inherit",
+                    fontFamily: StrCast(this.layoutDoc._fontFamily) || "inherit",
                     letterSpacing: StrCast(this.layoutDoc.letterSpacing),
                     textTransform: StrCast(this.layoutDoc.textTransform) as any,
                     paddingLeft: NumCast(this.layoutDoc._xPadding),
diff --git a/src/client/views/nodes/SliderBox.tsx b/src/client/views/nodes/SliderBox.tsx
index b2d451ea8..cb2526769 100644
--- a/src/client/views/nodes/SliderBox.tsx
+++ b/src/client/views/nodes/SliderBox.tsx
@@ -56,7 +56,7 @@ export class SliderBox extends ViewBoxBaseComponent<FieldViewProps, SliderDocume
                 style={{ boxShadow: this.layoutDoc.opacity === 0 ? undefined : StrCast(this.layoutDoc.boxShadow, "") }}>
                 <div className="sliderBox-mainButton" onContextMenu={this.specificContextMenu} style={{
                     background: StrCast(this.layoutDoc.backgroundColor), color: StrCast(this.layoutDoc.color, "black"),
-                    fontSize: NumCast(this.layoutDoc.fontSize), letterSpacing: StrCast(this.layoutDoc.letterSpacing)
+                    fontSize: NumCast(this.layoutDoc._fontSize), letterSpacing: StrCast(this.layoutDoc.letterSpacing)
                 }} >
                     <Slider
                         mode={2}
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index f24ad42b2..7a0be8863 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -30,6 +30,8 @@ export const documentSchema = createSchema({
     _replacedChrome: "string",  // what the default chrome is replaced with. Currently only supports the value of 'replaced' for PresBox's.
     _chromeStatus: "string",    // determines the state of the collection chrome. values allowed are 'replaced', 'enabled', 'disabled', 'collapsed'
     _freezeChildDimensions: "boolean", // freezes child document dimensions (e.g., used by time/pivot view to make sure all children will be scaled to fit their display rectangle)
+    _fontSize: "number",
+    _fontFamily: "string",
     isInPlaceContainer: "boolean",// whether the marked object will display addDocTab() calls that target "inPlace" destinations
     color: "string",            // foreground color of document
     backgroundColor: "string",  // background color of document
-- 
cgit v1.2.3-70-g09d2

