From b4ef60552f226e4022fac5092ea66f1b685bb08c Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Mon, 22 Jul 2019 18:50:26 -0400
Subject: Started adding schema functionality

---
 src/client/views/nodes/DocumentView.tsx | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

(limited to 'src/client/views/nodes/DocumentView.tsx')

diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 1c03bfc81..7280dbcf6 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -37,6 +37,7 @@ import { RouteStore } from '../../../server/RouteStore';
 import { FormattedTextBox } from './FormattedTextBox';
 import { OverlayView } from '../OverlayView';
 import { ScriptingRepl } from '../ScriptingRepl';
+import { ClientUtils } from '../../util/ClientUtils';
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
 library.add(fa.faTrash);
@@ -58,6 +59,7 @@ library.add(fa.faCrosshairs);
 library.add(fa.faDesktop);
 library.add(fa.faUnlock);
 library.add(fa.faLock);
+library.add(fa.faLaptopCode);
 
 
 // const linkSchema = createSchema({
@@ -551,17 +553,18 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 this.props.removeDocument && this.props.removeDocument(this.props.Document);
             }, icon: "window-restore"
         });
-        cm.addItem({
-            description: "Find aliases", event: async () => {
-                const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document);
-                this.props.addDocTab && this.props.addDocTab(Docs.Create.SchemaDocument(["title"], aliases, {}), undefined, "onRight"); // bcz: dataDoc?
-            }, icon: "search"
-        });
-        cm.addItem({ description: "Add Repl", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) });
-        cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" });
+        // cm.addItem({
+        //     description: "Find aliases", event: async () => {
+        //         const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document);
+        //         this.props.addDocTab && this.props.addDocTab(Docs.Create.SchemaDocument(["title"], aliases, {}), undefined, "onRight"); // bcz: dataDoc?
+        //     }, icon: "search"
+        // });
+        cm.addItem({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) });
         cm.addItem({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" });
-        cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "link" });
-        cm.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" });
+        if (!ClientUtils.RELEASE) {
+            cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "link" });
+            cm.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" });
+        }
         cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" });
         type User = { email: string, userDocumentId: string };
         let usersMenu: ContextMenuProps[] = [];
-- 
cgit v1.2.3-70-g09d2


From 5bc848bde4f37ec3dc812b22d81ded16f2a86f93 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 24 Jul 2019 00:35:29 -0400
Subject: fixed reordering tree view items.  restored double-click to view
 detail view.

---
 src/client/views/collections/CollectionTreeView.tsx | 2 +-
 src/client/views/nodes/DocumentView.tsx             | 1 +
 src/new_fields/Doc.ts                               | 8 ++++++++
 3 files changed, 10 insertions(+), 1 deletion(-)

(limited to 'src/client/views/nodes/DocumentView.tsx')

diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 2ff9e43fe..fe636942c 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -448,7 +448,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 dataDoc={dataDoc}
                 containingCollection={containingCollection}
                 treeViewId={treeViewId}
-                key={child[Id] + "child " + i}
+                key={child[Id]}
                 indentDocument={indent}
                 renderDepth={renderDepth}
                 deleteDoc={remove}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 09a1b49fe..8d7b3d835 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -295,6 +295,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         if (this._doubleTap && this.props.renderDepth) {
             let fullScreenAlias = Doc.MakeAlias(this.props.Document);
             fullScreenAlias.templates = new List<string>();
+            Doc.UseDetailLayout(fullScreenAlias);
             this.props.addDocTab(fullScreenAlias, this.dataDoc, "inTab");
             SelectionManager.DeselectAll();
             this.props.Document.libraryBrush = undefined;
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 2a697e621..a1241aac3 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -463,4 +463,12 @@ export namespace Doc {
         d.layout !== miniLayout ? miniLayout && (d.layout = d.miniLayout) : detailLayout && (d.layout = detailLayout);
         if (d.layout === detailLayout) Doc.GetProto(d).nativeWidth = Doc.GetProto(d).nativeHeight = undefined;
     }
+    export async function UseDetailLayout(d: Doc) {
+        let miniLayout = await PromiseValue(d.miniLayout);
+        let detailLayout = await PromiseValue(d.detailedLayout);
+        if (miniLayout && d.layout === miniLayout && detailLayout) {
+            d.layout = detailLayout;
+            Doc.GetProto(d).nativeWidth = Doc.GetProto(d).nativeHeight = undefined;
+        }
+    }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 52dc823c6a4c4b3e8deb994358a10acca4b6bd6c Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Wed, 24 Jul 2019 12:31:07 -0400
Subject: Added transitions

---
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx    | 3 ---
 src/client/views/nodes/CollectionFreeFormDocumentView.tsx              | 3 ++-
 src/client/views/nodes/DocumentView.tsx                                | 1 -
 3 files changed, 2 insertions(+), 5 deletions(-)

(limited to 'src/client/views/nodes/DocumentView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 70c43bbec..7a9b94bfd 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -503,11 +503,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                         onError(script.errors.map(error => error.messageText).join("\n"));
                         return;
                     }
-                    const docs = DocListCast(doc[dataKey]);
-                    docs.map(d => d.transition = "transform 1s");
                     doc[key] = new ScriptField(script);
                     overlayDisposer();
-                    setTimeout(() => docs.map(d => d.transition = undefined), 1200);
                 }} />;
                 overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, options);
             };
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index b09538d1a..389b9f68b 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -82,6 +82,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     }
 
     render() {
+        const hasPosition = this.props.x !== undefined || this.props.y !== undefined;
         return (
             <div className="collectionFreeFormDocumentView-container"
                 style={{
@@ -90,7 +91,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                     backgroundColor: "transparent",
                     borderRadius: this.borderRounding(),
                     transform: this.transform,
-                    transition: StrCast(this.props.Document.transition),
+                    transition: hasPosition ? "transform 1s" : StrCast(this.props.Document.transition),
                     width: this.width,
                     height: this.height,
                     zIndex: this.Document.zIndex || 0,
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 0a3633da2..138d065c6 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -565,7 +565,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             cm.addItem({ description: "Toggle detail", event: () => Doc.ToggleDetailLayout(this.props.Document), icon: "image" });
         }
         cm.addItem({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) });
-        cm.addItem({ description: "Add Repl", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) });
         cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" });
         cm.addItem({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" });
         if (!ClientUtils.RELEASE) {
-- 
cgit v1.2.3-70-g09d2


From ab78fa317bdbcf6fcbceb35586604d90c7277446 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 24 Jul 2019 22:48:39 -0400
Subject: allow independent iconization of iconized aliases

---
 src/client/views/DocumentDecorations.tsx |  2 +-
 src/client/views/nodes/DocumentView.tsx  | 15 +++++++--------
 2 files changed, 8 insertions(+), 9 deletions(-)

(limited to 'src/client/views/nodes/DocumentView.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 989b35581..6fecbd3a7 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -304,7 +304,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         iconDoc.height = Number(MINIMIZED_ICON_SIZE);
         iconDoc.x = NumCast(doc.x);
         iconDoc.y = NumCast(doc.y) - 24;
-        iconDoc.maximizedDocs = new List<Doc>(selected.map(s => s.props.Document.proto!));
+        iconDoc.maximizedDocs = new List<Doc>(selected.map(s => s.props.Document));
         selected.length === 1 && (doc.minimizedDoc = iconDoc);
         selected[0].props.addDocument && selected[0].props.addDocument(iconDoc, false);
         return iconDoc;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 35a4613af..88a894cd0 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -195,10 +195,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 DocumentView.animateBetweenIconFunc(doc, width, height, stime, maximizing, cb);
             }
             else {
-                Doc.GetProto(doc).isMinimized = !maximizing;
-                Doc.GetProto(doc).isIconAnimating = undefined;
+                doc.isMinimized = !maximizing;
+                doc.isIconAnimating = undefined;
             }
-            Doc.GetProto(doc).willMaximize = false;
+            doc.willMaximize = false;
         },
             2);
     }
@@ -319,20 +319,19 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 expandedDocs = summarizedDocs ? [...summarizedDocs, ...expandedDocs] : expandedDocs;
                 // let expandedDocs = [...(subBulletDocs ? subBulletDocs : []), ...(maximizedDocs ? maximizedDocs : []), ...(summarizedDocs ? summarizedDocs : []),];
                 if (expandedDocs.length) {   // bcz: need a better way to associate behaviors with click events on widget-documents
-                    let expandedProtoDocs = expandedDocs.map(doc => Doc.GetProto(doc));
                     let maxLocation = StrCast(this.props.Document.maximizeLocation, "inPlace");
                     let getDispDoc = (target: Doc) => Object.getOwnPropertyNames(target).indexOf("isPrototype") === -1 ? target : Doc.MakeDelegate(target);
                     if (altKey || ctrlKey) {
                         maxLocation = this.props.Document.maximizeLocation = (ctrlKey ? maxLocation : (maxLocation === "inPlace" || !maxLocation ? "inTab" : "inPlace"));
                         if (!maxLocation || maxLocation === "inPlace") {
-                            let hadView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedProtoDocs[0], this.props.ContainingCollectionView);
+                            let hadView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedDocs[0], this.props.ContainingCollectionView);
                             let wasMinimized = !hadView && expandedDocs.reduce((min, d) => !min && !BoolCast(d.IsMinimized, false), false);
                             expandedDocs.forEach(maxDoc => Doc.GetProto(maxDoc).isMinimized = false);
-                            let hasView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedProtoDocs[0], this.props.ContainingCollectionView);
+                            let hasView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedDocs[0], this.props.ContainingCollectionView);
                             if (!hasView) {
                                 this.props.addDocument && expandedDocs.forEach(async maxDoc => this.props.addDocument!(getDispDoc(maxDoc), false));
                             }
-                            expandedProtoDocs.forEach(maxDoc => maxDoc.isMinimized = wasMinimized);
+                            expandedDocs.forEach(maxDoc => maxDoc.isMinimized = wasMinimized);
                         }
                     }
                     if (maxLocation && maxLocation !== "inPlace" && CollectionDockingView.Instance) {
@@ -344,7 +343,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                         }
                     } else {
                         let scrpt = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(NumCast(this.Document.width) / 2, NumCast(this.Document.height) / 2);
-                        this.collapseTargetsToPoint(scrpt, expandedProtoDocs);
+                        this.collapseTargetsToPoint(scrpt, expandedDocs);
                     }
                 }
                 else if (linkedDocs.length) {
-- 
cgit v1.2.3-70-g09d2


From eceff76609deaa3e7a60c686b62cb4fd15e9699b Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 25 Jul 2019 15:00:16 -0400
Subject: several fixes and added basic fields to treeview display

---
 .vscode/launch.json                                |   4 -
 .../views/collections/CollectionTreeView.tsx       | 106 +++++++++++++--------
 src/client/views/nodes/DocumentView.tsx            |   4 +-
 src/client/views/nodes/ImageBox.tsx                |   2 +-
 src/client/views/search/SearchItem.tsx             |   6 +-
 src/new_fields/Doc.ts                              |   2 +-
 6 files changed, 71 insertions(+), 53 deletions(-)

(limited to 'src/client/views/nodes/DocumentView.tsx')

diff --git a/.vscode/launch.json b/.vscode/launch.json
index fd67a7647..822a06024 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -7,10 +7,6 @@
         {
             "type": "chrome",
             "request": "launch",
-            "runtimeArgs": [
-                "--enable-logging",
-                "--v=1"
-            ],
             "name": "Launch Chrome against localhost",
             "sourceMaps": true,
             "breakOnLoad": true,
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 006de0c70..ff3221ada 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -3,7 +3,7 @@ import { faAngleRight, faCamera, faExpand, faTrash, faBell, faCaretDown, faCaret
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, observable, trace, untracked } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, DocListCast, HeightSym, WidthSym, Opt } from '../../../new_fields/Doc';
+import { Doc, DocListCast, HeightSym, WidthSym, Opt, Field } from '../../../new_fields/Doc';
 import { Id } from '../../../new_fields/FieldSymbols';
 import { List } from '../../../new_fields/List';
 import { Document, listSpec } from '../../../new_fields/Schema';
@@ -26,6 +26,8 @@ import { CollectionSubView } from "./CollectionSubView";
 import "./CollectionTreeView.scss";
 import React = require("react");
 import { LinkManager } from '../../util/LinkManager';
+import { ComputedField } from '../../../new_fields/ScriptField';
+import { KeyValueBox } from '../nodes/KeyValueBox';
 
 
 export interface TreeViewProps {
@@ -68,8 +70,7 @@ class TreeView extends React.Component<TreeViewProps> {
     private _header?: React.RefObject<HTMLDivElement> = React.createRef();
     private _treedropDisposer?: DragManager.DragDropDisposer;
     private _dref = React.createRef<HTMLDivElement>();
-    @observable __chosenKey: string = "";
-    @computed get _chosenKey() { return this.__chosenKey ? this.__chosenKey : this.fieldKey; }
+    @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, "data"); }
     @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.document.maxEmbedHeight, 300); }
     @observable _collapsed: boolean = true;
 
@@ -125,12 +126,12 @@ class TreeView extends React.Component<TreeViewProps> {
         }
     }
     onPointerLeave = (e: React.PointerEvent): void => {
-        this.props.document.libraryBrush = undefined;
+        this.props.document.libraryBrush = false;
         this._header!.current!.className = "treeViewItem-header";
         document.removeEventListener("pointermove", this.onDragMove, true);
     }
     onDragMove = (e: PointerEvent): void => {
-        this.props.document.libraryBrush = undefined;
+        this.props.document.libraryBrush = false;
         let x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY);
         let rect = this._header!.current!.getBoundingClientRect();
         let bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
@@ -191,25 +192,6 @@ class TreeView extends React.Component<TreeViewProps> {
         OnTab={() => this.props.indentDocument && this.props.indentDocument()}
     />)
 
-    @computed get keyList() {
-        let target = this.props.document;
-        let keys = Array.from(Object.keys(target));
-        if (target.proto instanceof Doc) {
-            keys.push(...Array.from(Object.keys(target.proto)));
-        }
-        let keyList: string[] = keys.reduce((l, key) => {
-            let listspec = DocListCast(target[key]);
-            if (listspec && listspec.length) return [...l, key];
-            return l;
-        }, [] as string[]);
-        keys.map(key => Cast(target[key], Doc) instanceof Doc && keyList.push(key));
-        if (LinkManager.Instance.getAllRelatedLinks(this.props.document).length > 0) keyList.push("links");
-        if (keyList.indexOf(this.fieldKey) !== -1) {
-            keyList.splice(keyList.indexOf(this.fieldKey), 1);
-        }
-        keyList.splice(0, 0, this.fieldKey);
-        return keyList.filter((item, index) => keyList.indexOf(item) >= index);
-    }
     /**
      * Renders the EditableView title element for placement into the tree.
      */
@@ -218,13 +200,9 @@ class TreeView extends React.Component<TreeViewProps> {
         let onItemDown = SetupDrag(reference, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId, true);
 
         let headerElements = (
-            <span className="collectionTreeView-keyHeader" key={this._chosenKey + "chosen"}
-                onPointerDown={action(() => {
-                    let ind = this.keyList.indexOf(this._chosenKey);
-                    ind = (ind + 1) % this.keyList.length;
-                    this.__chosenKey = this.keyList[ind];
-                })} >
-                {this._chosenKey}
+            <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView}
+                onPointerDown={action(() => this.props.document.treeViewExpandedView = this.treeViewExpandedView === "data" ? "fields" : this.treeViewExpandedView === "fields" && this.props.document.layout ? "layout" : "data")}>
+                {this.treeViewExpandedView}
             </span>);
         let dataDocs = CollectionDockingView.Instance ? Cast(CollectionDockingView.Instance.props.Document[this.fieldKey], listSpec(Doc), []) : [];
         let openRight = dataDocs && dataDocs.indexOf(this.dataDoc) !== -1 ? (null) : (
@@ -249,7 +227,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 view7
-            ContextMenu.Instance.addItem({ description: (BoolCast(this.props.document.embed) ? "Collapse" : "Expand") + " inline", event: () => this.props.document.embed = !BoolCast(this.props.document.embed), icon: "expand" });
             if (NumCast(this.props.document.viewType) !== CollectionViewType.Docking) {
                 ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, this.resolvedDataDoc, "inTab"), icon: "folder" });
                 ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, this.resolvedDataDoc, "onRight"), icon: "caret-square-right" });
@@ -311,8 +288,8 @@ class TreeView extends React.Component<TreeViewProps> {
 
     renderLinks = () => {
         let ele: JSX.Element[] = [];
-        let remDoc = (doc: Doc) => this.remove(doc, this._chosenKey);
-        let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.props.document, this._chosenKey, doc, addBefore, before);
+        let remDoc = (doc: Doc) => this.remove(doc, this.fieldKey);
+        let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.props.document, this.fieldKey, doc, addBefore, before);
         let groups = LinkManager.Instance.getRelatedGroupedLinks(this.props.document);
         groups.forEach((groupLinkDocs, groupType) => {
             // let destLinks = groupLinkDocs.map(d => LinkManager.Instance.getOppositeAnchor(d, this.props.document));
@@ -358,20 +335,65 @@ class TreeView extends React.Component<TreeViewProps> {
 
     noOverlays = (doc: Doc) => ({ title: "", caption: "" });
 
+    expandedField = (doc?: Doc) => {
+        if (!doc) return <div />;
+        let realDoc = doc;
+
+        let ids: { [key: string]: string } = {};
+        Object.keys(doc).forEach(key => {
+            if (!(key in ids) && realDoc[key] !== ComputedField.undefined) {
+                ids[key] = key;
+            }
+        });
+
+        let rows: JSX.Element[] = [];
+        for (let key of Object.keys(ids).sort()) {
+            let contents = realDoc[key] ? realDoc[key] : undefined;
+            let contentElement: JSX.Element[] | JSX.Element = [];
+
+            if (contents instanceof Doc || Cast(contents, listSpec(Doc))) {
+                let docList = contents;
+                let remDoc = (doc: Doc) => this.remove(doc, key);
+                let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before);
+                contentElement = key === "links" ? this.renderLinks() :
+                    TreeView.GetChildElements(docList instanceof Doc ? [docList as Doc] : DocListCast(docList), this.props.treeViewId, realDoc, undefined, key, addDoc, remDoc, this.move,
+                        this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth);
+            } else {
+                contentElement = <EditableView
+                    key="editableView"
+                    contents={contents ? contents.toString() : "null"}
+                    height={13}
+                    fontSize={12}
+                    GetValue={() => Field.toKeyValueString(realDoc, key)}
+                    SetValue={(value: string) => KeyValueBox.SetField(realDoc, key, value)} />;
+            }
+            rows.push(<div style={{ display: "flex" }} key={key}>
+                <span style={{ fontWeight: "bold" }}>{key + ":"}</span>
+                &nbsp;
+                {contentElement}
+            </div>);
+        }
+        return rows;
+    }
+
     render() {
         let contentElement: (JSX.Element | null) = null;
-        let docList = Cast(this.dataDoc[this._chosenKey], listSpec(Doc));
-        let remDoc = (doc: Doc) => this.remove(doc, this._chosenKey);
-        let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, this._chosenKey, doc, addBefore, before);
+        let docList = Cast(this.dataDoc[this.fieldKey], listSpec(Doc));
+        let remDoc = (doc: Doc) => this.remove(doc, this.fieldKey);
+        let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc, addBefore, before);
 
         if (!this._collapsed) {
-            if (!this.props.document.embed) {
-                let doc = Cast(this.props.document[this._chosenKey], Doc);
-                contentElement = <ul key={this._chosenKey + "more"}>
-                    {this._chosenKey === "links" ? this.renderLinks() :
-                        TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this.props.document, this.resolvedDataDoc, this._chosenKey, addDoc, remDoc, this.move,
+            if (this.treeViewExpandedView === "data") {
+                let doc = Cast(this.props.document[this.fieldKey], Doc);
+                contentElement = <ul key={this.fieldKey + "more"}>
+                    {this.fieldKey === "links" ? this.renderLinks() :
+                        TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this.props.document, this.resolvedDataDoc, this.fieldKey, addDoc, remDoc, this.move,
                             this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth)}
                 </ul >;
+            } else if (this.treeViewExpandedView === "fields") {
+                contentElement = <ul><div ref={this._dref} style={{ display: "inline-block" }} key={this.props.document[Id] + this.props.document.title}>
+                    {this.expandedField(this.dataDoc)}
+                </div></ul>;
             } else {
                 let layoutDoc = this.props.document;
                 contentElement = <div ref={this._dref} style={{ display: "inline-block", height: this.docHeight() }} key={this.props.document[Id] + this.props.document.title}>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b39c77adb..b5e64ed19 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -300,7 +300,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             Doc.UseDetailLayout(fullScreenAlias);
             this.props.addDocTab(fullScreenAlias, this.dataDoc, "inTab");
             SelectionManager.DeselectAll();
-            this.props.Document.libraryBrush = undefined;
+            this.props.Document.libraryBrush = false;
         }
         else if (CurrentUserUtils.MainDocId !== this.props.Document[Id] &&
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
@@ -612,7 +612,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     onPointerEnter = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = true; };
-    onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = undefined; };
+    onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; };
 
     isSelected = () => SelectionManager.IsSelected(this);
     @action select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); };
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 3d77696fe..14208ce17 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -175,7 +175,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
                 const url = Utils.prepend(files[0]);
                 // upload to server with known URL 
                 let audioDoc = Docs.Create.AudioDocument(url, { title: "audio test", x: NumCast(self.props.Document.x), y: NumCast(self.props.Document.y), width: 200, height: 32 });
-                audioDoc.embed = true;
+                audioDoc.treeViewExpandedView = "layout";
                 let audioAnnos = Cast(self.extensionDoc.audioAnnotations, listSpec(Doc));
                 if (audioAnnos === undefined) {
                     self.extensionDoc.audioAnnotations = new List([audioDoc]);
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index a995140e2..5c2ced2eb 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -205,13 +205,13 @@ export class SearchItem extends React.Component<SearchItemProps> {
 
                 let doc1 = Cast(this.props.doc.anchor1, Doc, null);
                 let doc2 = Cast(this.props.doc.anchor2, Doc, null);
-                doc1 && (doc1.libraryBrush = undefined);
-                doc2 && (doc2.libraryBrush = undefined);
+                doc1 && (doc1.libraryBrush = false);
+                doc2 && (doc2.libraryBrush = false);
             }
         } else {
             let docViews: DocumentView[] = DocumentManager.Instance.getAllDocumentViews(this.props.doc);
             docViews.forEach(element => {
-                element.props.Document.libraryBrush = undefined;
+                element.props.Document.libraryBrush = false;
             });
         }
     }
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 64b4acb7b..c37c0fd22 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -380,7 +380,7 @@ export namespace Doc {
         }
         if (expandedTemplateLayout === undefined) {
             setTimeout(() =>
-                dataDoc[expandedLayoutFieldKey] = Doc.MakeDelegate(templateLayoutDoc, undefined, templateLayoutDoc.title + ".layout"), 0);
+                dataDoc[expandedLayoutFieldKey] = Doc.MakeDelegate(templateLayoutDoc, undefined, "["+templateLayoutDoc.title + "]"), 0);
         }
         return templateLayoutDoc; // use the templateLayout when it's not a template or the expandedTemplate is pending.
     }
-- 
cgit v1.2.3-70-g09d2

