From 3958654925e92b1046b3ed5d49160514b6e48258 Mon Sep 17 00:00:00 2001
From: geireann <geireann.lindfield@gmail.com>
Date: Tue, 6 Jun 2023 14:36:21 -0400
Subject: added rec stuff and begun updating components

---
 .../views/newlightbox/ExploreView/ExploreView.tsx  | 30 ++++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 src/client/views/newlightbox/ExploreView/ExploreView.tsx

(limited to 'src/client/views/newlightbox/ExploreView/ExploreView.tsx')

diff --git a/src/client/views/newlightbox/ExploreView/ExploreView.tsx b/src/client/views/newlightbox/ExploreView/ExploreView.tsx
new file mode 100644
index 000000000..855bfd9e2
--- /dev/null
+++ b/src/client/views/newlightbox/ExploreView/ExploreView.tsx
@@ -0,0 +1,30 @@
+import './ExploreView.scss';
+import { IBounds, IExploreView, emptyBounds } from "./utils";
+import { IRecommendation } from "../components";
+import * as React from 'react';
+import { NewLightboxView } from '../NewLightboxView';
+import { StrCast } from '../../../../fields/Types';
+
+
+
+export const ExploreView = (props: IExploreView) => {
+    const { recs, bounds=emptyBounds } = props
+    
+    return <div className={`exploreView-container`}>
+        {recs && recs.map((rec) => {
+            console.log(rec.embedding, bounds)
+            const x_bound: number = Math.max(Math.abs(bounds.max_x), Math.abs(bounds.min_x))
+            const y_bound: number = Math.max(Math.abs(bounds.max_y), Math.abs(bounds.min_y))
+            console.log(x_bound, y_bound)
+            if (rec.embedding) {
+                const x = (rec.embedding.x / x_bound) * 50;
+                const y = (rec.embedding.y / y_bound) * 50;
+                console.log(x, y)
+                return <div className={`exploreView-doc`} onClick={() => {}} style={{top: `calc(50% + ${y}%)`, left: `calc(50% + ${x}%)`}}>
+                    {rec.title}
+                </div>
+            } else return (null)
+        })}
+        <div className={`exploreView-doc`} style={{top: `calc(50% + ${0}%)`, left: `calc(50% + ${0}%)`, background: '#073763', color: 'white'}}>{StrCast(NewLightboxView.NewLightboxDoc?.title)}</div>
+    </div>
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 7edcc150d013343cb7feca49ce43228b99e6c7e5 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 28 Jul 2023 11:33:06 -0400
Subject: cleanup of compile errors

---
 src/client/documents/Documents.ts                  |   1 -
 src/client/util/GroupManager.tsx                   |  30 ++--
 src/client/util/GroupMemberView.tsx                | 104 +++++--------
 src/client/views/DocumentButtonBar.tsx             |   1 -
 .../views/newlightbox/ButtonMenu/ButtonMenu.tsx    |  79 +++++-----
 .../views/newlightbox/ExploreView/ExploreView.tsx  |  53 ++++---
 .../components/Recommendation/Recommendation.tsx   | 171 +++++++++++----------
 7 files changed, 211 insertions(+), 228 deletions(-)

(limited to 'src/client/views/newlightbox/ExploreView/ExploreView.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index f22fa9f17..c5a9ce824 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -58,7 +58,6 @@ import { SliderBox } from '../views/nodes/SliderBox';
 import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox';
 import { PresBox } from '../views/nodes/trails/PresBox';
 import { PresElementBox } from '../views/nodes/trails/PresElementBox';
-import { ImportElementBox } from '../views/nodes/importBox/ImportElementBox';
 import { VideoBox } from '../views/nodes/VideoBox';
 import { WebBox } from '../views/nodes/WebBox';
 import { SearchBox } from '../views/search/SearchBox';
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index 5802d5ee0..e406d89e7 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -15,7 +15,7 @@ import { SharingManager, User } from './SharingManager';
 import { listSpec } from '../../fields/Schema';
 import { DateField } from '../../fields/DateField';
 import { Id } from '../../fields/FieldSymbols';
-import { Button, IconButton, Size } from 'browndash-components';
+import { Button, IconButton, Size, Type } from 'browndash-components';
 
 /**
  * Interface for options for the react-select component
@@ -281,7 +281,7 @@ export class GroupManager extends React.Component<{}> {
      */
     private get groupCreationModal() {
         const contents = (
-            <div className="group-create" style={{background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor)}}>
+            <div className="group-create" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
                 <div className="group-heading" style={{ marginBottom: 0 }}>
                     <p>
                         <b>New Group</b>
@@ -297,10 +297,10 @@ export class GroupManager extends React.Component<{}> {
                         />
                     </div>
                 </div>
-                <div className="group-input" style={{border: StrCast(Doc.UserDoc().userColor)}} >
+                <div className="group-input" style={{ border: StrCast(Doc.UserDoc().userColor) }}>
                     <input ref={this.inputRef} onKeyDown={this.handleKeyDown} autoFocus type="text" placeholder="Group name" onChange={action(() => (this.buttonColour = this.inputRef.current?.value ? 'black' : '#979797'))} />
                 </div>
-                <div style={{border: StrCast(Doc.UserDoc().userColor)}}>
+                <div style={{ border: StrCast(Doc.UserDoc().userColor) }}>
                     <Select
                         className="select-users"
                         isMulti
@@ -331,8 +331,8 @@ export class GroupManager extends React.Component<{}> {
                         }}
                     />
                 </div>
-                <div className={"create-button"}>
-                    <Button text={"Create"} type={"tertiary"} color={StrCast(Doc.UserDoc().userColor)} onClick={this.createGroup} />
+                <div className={'create-button'}>
+                    <Button text={'Create'} type={Type.TERT} color={StrCast(Doc.UserDoc().userColor)} onClick={this.createGroup} />
                 </div>
             </div>
         );
@@ -366,29 +366,25 @@ export class GroupManager extends React.Component<{}> {
         const groups = this.groupSort === 'ascending' ? this.allGroups.sort(sortGroups) : this.groupSort === 'descending' ? this.allGroups.sort(sortGroups).reverse() : this.allGroups;
 
         return (
-            <div className="group-interface" style={{background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor)}}>
+            <div className="group-interface" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
                 {this.groupCreationModal}
                 {this.currentGroup ? <GroupMemberView group={this.currentGroup} onCloseButtonClick={action(() => (this.currentGroup = undefined))} /> : null}
                 <div className="group-heading">
                     <p>
                         <b>Manage Groups</b>
                     </p>
-                    <Button icon={<FontAwesomeIcon icon={'plus'}/>} iconPlacement={'left'} text={"Create Group"} type={"tertiary"} color={StrCast(Doc.UserDoc().userColor)} onClick={action(() => (this.createGroupModalOpen = true))} />
-                    <div className={'close-button'} >
-                        <Button
-                            icon={<FontAwesomeIcon icon={'times'} size={'lg'} />}
-                            onClick={this.close}
-                            color={StrCast(Doc.UserDoc().userColor)}
-                        />
+                    <Button icon={<FontAwesomeIcon icon={'plus'} />} iconPlacement={'left'} text={'Create Group'} type={Type.TERT} color={StrCast(Doc.UserDoc().userColor)} onClick={action(() => (this.createGroupModalOpen = true))} />
+                    <div className={'close-button'}>
+                        <Button icon={<FontAwesomeIcon icon={'times'} size={'lg'} />} onClick={this.close} color={StrCast(Doc.UserDoc().userColor)} />
                     </div>
                 </div>
                 <div className="main-container">
                     <div className="sort-groups" onClick={action(() => (this.groupSort = this.groupSort === 'ascending' ? 'descending' : this.groupSort === 'descending' ? 'none' : 'ascending'))}>
                         Name
-                        <IconButton icon={<FontAwesomeIcon icon={this.groupSort === 'ascending' ? 'caret-up' : this.groupSort === 'descending' ? 'caret-down' : 'caret-right'}/>} size={Size.XSMALL} color={StrCast(Doc.UserDoc().userColor)} />
+                        <IconButton icon={<FontAwesomeIcon icon={this.groupSort === 'ascending' ? 'caret-up' : this.groupSort === 'descending' ? 'caret-down' : 'caret-right'} />} size={Size.XSMALL} color={StrCast(Doc.UserDoc().userColor)} />
                     </div>
-                    <div className={'style-divider'} style={{background: StrCast(Doc.UserDoc().userColor)}}/>
-                    <div className="group-body" style={{background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor)}}>
+                    <div className={'style-divider'} style={{ background: StrCast(Doc.UserDoc().userColor) }} />
+                    <div className="group-body" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
                         {groups.map(group => (
                             <div className="group-row" key={StrCast(group.title || group.groupName)}>
                                 <div className="group-name">{StrCast(group.title || group.groupName)}</div>
diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx
index f2050dc61..057f94f64 100644
--- a/src/client/util/GroupMemberView.tsx
+++ b/src/client/util/GroupMemberView.tsx
@@ -1,14 +1,14 @@
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, observable } from "mobx";
-import { observer } from "mobx-react";
-import * as React from "react";
-import Select from "react-select";
-import { Doc } from "../../fields/Doc";
-import { StrCast } from "../../fields/Types";
-import { MainViewModal } from "../views/MainViewModal";
-import { GroupManager, UserOptions } from "./GroupManager";
-import "./GroupMemberView.scss";
-import { Button, IconButton, Size } from "browndash-components";
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, observable } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import Select from 'react-select';
+import { Doc } from '../../fields/Doc';
+import { StrCast } from '../../fields/Types';
+import { MainViewModal } from '../views/MainViewModal';
+import { GroupManager, UserOptions } from './GroupManager';
+import './GroupMemberView.scss';
+import { Button, IconButton, Size, Type } from 'browndash-components';
 
 interface GroupMemberViewProps {
     group: Doc;
@@ -17,44 +17,37 @@ interface GroupMemberViewProps {
 
 @observer
 export class GroupMemberView extends React.Component<GroupMemberViewProps> {
-
-    @observable private memberSort: "ascending" | "descending" | "none" = "none";
+    @observable private memberSort: 'ascending' | 'descending' | 'none' = 'none';
 
     private get editingInterface() {
         let members: string[] = this.props.group ? JSON.parse(StrCast(this.props.group.members)) : [];
-        members = this.memberSort === "ascending" ? members.sort() : this.memberSort === "descending" ? members.sort().reverse() : members;
+        members = this.memberSort === 'ascending' ? members.sort() : this.memberSort === 'descending' ? members.sort().reverse() : members;
 
         const options: UserOptions[] = this.props.group ? GroupManager.Instance.options.filter(option => !(JSON.parse(StrCast(this.props.group.members)) as string[]).includes(option.value)) : [];
 
         const hasEditAccess = GroupManager.Instance.hasEditAccess(this.props.group);
 
-        return (!this.props.group ? null :
-            <div className="editing-interface" style={{background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor)}}>
+        return !this.props.group ? null : (
+            <div className="editing-interface" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
                 <div className="editing-header">
                     <input
                         className="group-title"
-                        style={{ marginLeft: !hasEditAccess ? "-14%" : 0 }}
+                        style={{ marginLeft: !hasEditAccess ? '-14%' : 0 }}
                         value={StrCast(this.props.group.title || this.props.group.groupName)}
-                        onChange={e => this.props.group.title = e.currentTarget.value}
-                        disabled={!hasEditAccess}
-                    >
-                    </input>
-                    <div className={"memberView-closeButton"} >
-                        <Button
-                            icon={<FontAwesomeIcon icon={'times'} size={'lg'} />}
-                            onClick={action(this.props.onCloseButtonClick)}
-                            color={StrCast(Doc.UserDoc().userColor)}
-                        />
+                        onChange={e => (this.props.group.title = e.currentTarget.value)}
+                        disabled={!hasEditAccess}></input>
+                    <div className={'memberView-closeButton'}>
+                        <Button icon={<FontAwesomeIcon icon={'times'} size={'lg'} />} onClick={action(this.props.onCloseButtonClick)} color={StrCast(Doc.UserDoc().userColor)} />
                     </div>
-                    {GroupManager.Instance.hasEditAccess(this.props.group) ?
+                    {GroupManager.Instance.hasEditAccess(this.props.group) ? (
                         <div className="group-buttons">
-                            <div style={{border: StrCast(Doc.UserDoc().userColor)}} >
-                                <Select 
+                            <div style={{ border: StrCast(Doc.UserDoc().userColor) }}>
+                                <Select
                                     className="add-member-dropdown"
                                     isSearchable={true}
                                     options={options}
                                     onChange={selectedOption => GroupManager.Instance.addMemberToGroup(this.props.group, (selectedOption as UserOptions).value)}
-                                    placeholder={"Add members"}
+                                    placeholder={'Add members'}
                                     value={null}
                                     styles={{
                                         control: () => ({
@@ -78,52 +71,33 @@ export class GroupMemberView extends React.Component<GroupMemberViewProps> {
                                     }}
                                 />
                             </div>
-                            <div className={"delete-button"}>
-                                <Button text={"Delete Group"} type={"tertiary"} color={StrCast(Doc.UserDoc().userColor)} onClick={() => GroupManager.Instance.deleteGroup(this.props.group)} />
+                            <div className={'delete-button'}>
+                                <Button text={'Delete Group'} type={Type.TERT} color={StrCast(Doc.UserDoc().userColor)} onClick={() => GroupManager.Instance.deleteGroup(this.props.group)} />
                             </div>
-                        </div> :
-                        null}
-                    <div
-                        className="sort-emails"
-                        style={{ paddingTop: hasEditAccess ? 0 : 35 }}
-                        onClick={action(() => this.memberSort = this.memberSort === "ascending" ? "descending" : this.memberSort === "descending" ? "none" : "ascending")}>
-                        Emails {this.memberSort === "ascending" ? "↑" : this.memberSort === "descending" ? "↓" : ""} {/* → */}
+                        </div>
+                    ) : null}
+                    <div className="sort-emails" style={{ paddingTop: hasEditAccess ? 0 : 35 }} onClick={action(() => (this.memberSort = this.memberSort === 'ascending' ? 'descending' : this.memberSort === 'descending' ? 'none' : 'ascending'))}>
+                        Emails {this.memberSort === 'ascending' ? '↑' : this.memberSort === 'descending' ? '↓' : ''} {/* → */}
                     </div>
                 </div>
-                <div className={'style-divider'} style={{background: StrCast(Doc.UserDoc().userColor)}}/>
-                <div className="editing-contents"
-                    style={{ height: hasEditAccess ? "62%" : "85%" }}
-                >
+                <div className={'style-divider'} style={{ background: StrCast(Doc.UserDoc().userColor) }} />
+                <div className="editing-contents" style={{ height: hasEditAccess ? '62%' : '85%' }}>
                     {members.map(member => (
-                        <div
-                            className="editing-row"
-                            key={member}
-                        >
-                            <div className="user-email">
-                                {member}
-                            </div>
-                            {hasEditAccess ?
-                                <div className={"remove-button"} onClick={() => GroupManager.Instance.removeMemberFromGroup(this.props.group, member)}>
+                        <div className="editing-row" key={member}>
+                            <div className="user-email">{member}</div>
+                            {hasEditAccess ? (
+                                <div className={'remove-button'} onClick={() => GroupManager.Instance.removeMemberFromGroup(this.props.group, member)}>
                                     <IconButton icon={<FontAwesomeIcon icon={'trash-alt'} />} size={Size.XSMALL} color={StrCast(Doc.UserDoc().userColor)} onClick={() => GroupManager.Instance.removeMemberFromGroup(this.props.group, member)} />
                                 </div>
-                                : null}
+                            ) : null}
                         </div>
                     ))}
                 </div>
             </div>
         );
-
     }
 
     render() {
-        return <MainViewModal
-            isDisplayed={true}
-            interactive={true}
-            contents={this.editingInterface}
-            dialogueBoxStyle={{ width: 400, height: 250 }}
-            closeOnExternalClick={this.props.onCloseButtonClick}
-        />;
+        return <MainViewModal isDisplayed={true} interactive={true} contents={this.editingInterface} dialogueBoxStyle={{ width: 400, height: 250 }} closeOnExternalClick={this.props.onCloseButtonClick} />;
     }
-
-
-}
\ No newline at end of file
+}
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 16f5ad168..6f5e9f5c0 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -589,7 +589,6 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                     <div style={{ position: 'absolute', zIndex: 1000 }}>
                         <LinkPopup
                             key="popup"
-                            showPopup={this._showLinkPopup}
                             linkCreated={link => (link.link_displayLine = !IsFollowLinkScript(this.props.views().lastElement()?.rootDoc.onClick))}
                             linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.(true)}
                             linkFrom={() => this.props.views().lastElement()?.rootDoc}
diff --git a/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx b/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx
index 0ede75407..ff17e5c12 100644
--- a/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx
+++ b/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx
@@ -1,6 +1,6 @@
 import './ButtonMenu.scss';
 import * as React from 'react';
-import { IButtonMenu } from "./utils";
+import { IButtonMenu } from './utils';
 import { NewLightboxView } from '../NewLightboxView';
 import { SelectionManager } from '../../../util/SelectionManager';
 import { CollectionDockingView } from '../../collections/CollectionDockingView';
@@ -11,43 +11,40 @@ import { MainView } from '../../MainView';
 import { action } from 'mobx';
 
 export const ButtonMenu = (props: IButtonMenu) => {
-    
-    return <div className={`newLightboxButtonMenu-container`}>
-        <div
-                    className="newLightboxView-navBtn"
-                    title="toggle fit width"
-                    onClick={e => {
-                        e.stopPropagation();
-                        NewLightboxView.NewLightboxDoc!._fitWidth = !NewLightboxView.NewLightboxDoc!._fitWidth;
-                    }}>
-                </div>
-                <div
-                    className="newLightboxView-tabBtn"
-                    title="open in tab"
-                    onClick={e => {
-                        e.stopPropagation();
-                        CollectionDockingView.AddSplit(NewLightboxView.NewLightboxDoc || NewLightboxView.NewLightboxDoc!, OpenWhereMod.none);
-                        SelectionManager.DeselectAll();
-                        NewLightboxView.SetNewLightboxDoc(undefined);
-                    }}>
-                </div>
-                <div
-                    className="newLightboxView-penBtn"
-                    title="toggle pen annotation"
-                    style={{ background: Doc.ActiveTool === InkTool.Pen ? 'white' : undefined }}
-                    onClick={e => {
-                        e.stopPropagation();
-                        Doc.ActiveTool = Doc.ActiveTool === InkTool.Pen ? InkTool.None : InkTool.Pen;
-                    }}>
-                </div>
-                <div
-                    className="newLightboxView-exploreBtn"
-                    title="toggle explore mode to navigate among documents only"
-                    style={{ background: MainView.Instance._exploreMode ? 'white' : undefined }}
-                    onClick={action(e => {
-                        e.stopPropagation();
-                        MainView.Instance._exploreMode = !MainView.Instance._exploreMode;
-                    })}>
-                </div>
-    </div>
-}
\ No newline at end of file
+    return (
+        <div className={`newLightboxButtonMenu-container`}>
+            <div
+                className="newLightboxView-navBtn"
+                title="toggle fit width"
+                onClick={e => {
+                    e.stopPropagation();
+                    NewLightboxView.LightboxDoc!._fitWidth = !NewLightboxView.LightboxDoc!._fitWidth;
+                }}></div>
+            <div
+                className="newLightboxView-tabBtn"
+                title="open in tab"
+                onClick={e => {
+                    e.stopPropagation();
+                    CollectionDockingView.AddSplit(NewLightboxView.LightboxDoc || NewLightboxView.LightboxDoc!, OpenWhereMod.none);
+                    SelectionManager.DeselectAll();
+                    NewLightboxView.SetNewLightboxDoc(undefined);
+                }}></div>
+            <div
+                className="newLightboxView-penBtn"
+                title="toggle pen annotation"
+                style={{ background: Doc.ActiveTool === InkTool.Pen ? 'white' : undefined }}
+                onClick={e => {
+                    e.stopPropagation();
+                    Doc.ActiveTool = Doc.ActiveTool === InkTool.Pen ? InkTool.None : InkTool.Pen;
+                }}></div>
+            <div
+                className="newLightboxView-exploreBtn"
+                title="toggle explore mode to navigate among documents only"
+                style={{ background: MainView.Instance._exploreMode ? 'white' : undefined }}
+                onClick={action(e => {
+                    e.stopPropagation();
+                    MainView.Instance._exploreMode = !MainView.Instance._exploreMode;
+                })}></div>
+        </div>
+    );
+};
diff --git a/src/client/views/newlightbox/ExploreView/ExploreView.tsx b/src/client/views/newlightbox/ExploreView/ExploreView.tsx
index 855bfd9e2..44a0bcd5f 100644
--- a/src/client/views/newlightbox/ExploreView/ExploreView.tsx
+++ b/src/client/views/newlightbox/ExploreView/ExploreView.tsx
@@ -1,30 +1,35 @@
 import './ExploreView.scss';
-import { IBounds, IExploreView, emptyBounds } from "./utils";
-import { IRecommendation } from "../components";
+import { IBounds, IExploreView, emptyBounds } from './utils';
+import { IRecommendation } from '../components';
 import * as React from 'react';
 import { NewLightboxView } from '../NewLightboxView';
 import { StrCast } from '../../../../fields/Types';
 
-
-
 export const ExploreView = (props: IExploreView) => {
-    const { recs, bounds=emptyBounds } = props
-    
-    return <div className={`exploreView-container`}>
-        {recs && recs.map((rec) => {
-            console.log(rec.embedding, bounds)
-            const x_bound: number = Math.max(Math.abs(bounds.max_x), Math.abs(bounds.min_x))
-            const y_bound: number = Math.max(Math.abs(bounds.max_y), Math.abs(bounds.min_y))
-            console.log(x_bound, y_bound)
-            if (rec.embedding) {
-                const x = (rec.embedding.x / x_bound) * 50;
-                const y = (rec.embedding.y / y_bound) * 50;
-                console.log(x, y)
-                return <div className={`exploreView-doc`} onClick={() => {}} style={{top: `calc(50% + ${y}%)`, left: `calc(50% + ${x}%)`}}>
-                    {rec.title}
-                </div>
-            } else return (null)
-        })}
-        <div className={`exploreView-doc`} style={{top: `calc(50% + ${0}%)`, left: `calc(50% + ${0}%)`, background: '#073763', color: 'white'}}>{StrCast(NewLightboxView.NewLightboxDoc?.title)}</div>
-    </div>
-}
\ No newline at end of file
+    const { recs, bounds = emptyBounds } = props;
+
+    return (
+        <div className={`exploreView-container`}>
+            {recs &&
+                recs.map(rec => {
+                    console.log(rec.embedding, bounds);
+                    const x_bound: number = Math.max(Math.abs(bounds.max_x), Math.abs(bounds.min_x));
+                    const y_bound: number = Math.max(Math.abs(bounds.max_y), Math.abs(bounds.min_y));
+                    console.log(x_bound, y_bound);
+                    if (rec.embedding) {
+                        const x = (rec.embedding.x / x_bound) * 50;
+                        const y = (rec.embedding.y / y_bound) * 50;
+                        console.log(x, y);
+                        return (
+                            <div className={`exploreView-doc`} onClick={() => {}} style={{ top: `calc(50% + ${y}%)`, left: `calc(50% + ${x}%)` }}>
+                                {rec.title}
+                            </div>
+                        );
+                    } else return null;
+                })}
+            <div className={`exploreView-doc`} style={{ top: `calc(50% + ${0}%)`, left: `calc(50% + ${0}%)`, background: '#073763', color: 'white' }}>
+                {StrCast(NewLightboxView.LightboxDoc?.title)}
+            </div>
+        </div>
+    );
+};
diff --git a/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx b/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx
index c0d357ad5..b9d05c531 100644
--- a/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx
+++ b/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx
@@ -1,5 +1,5 @@
 import * as React from 'react';
-import { IRecommendation } from "./utils";
+import { IRecommendation } from './utils';
 import './Recommendation.scss';
 import { getType } from '../../utils';
 import { FaEyeSlash } from 'react-icons/fa';
@@ -9,82 +9,95 @@ import { Doc } from '../../../../../fields/Doc';
 import { Docs } from '../../../../documents/Documents';
 
 export const Recommendation = (props: IRecommendation) => {
-    const {title, data, type, text, transcript, loading, source, previewUrl, related_concepts, distance, docId} = props
-    
-    return <div className={`recommendation-container ${loading && 'loading'} ${previewUrl && 'previewUrl'}`} onClick={() => {
-        let doc: Doc | null = null;
-        if (source == "Dash" && docId) {
-            const docView = DocumentManager.Instance.getDocumentViewById(docId)
-            if (docView) {
-                doc = docView.rootDoc;
-            }
-        } else if (data) {
-            console.log(data, type)
-            switch(type) {
-                case "YouTube":
-                    console.log('create ', type, 'document')
-                    doc = Docs.Create.VideoDocument(data, { title: title, _width: 400, _height: 315, transcript: transcript })
-                    break;
-                case "Video":
-                    console.log('create ', type, 'document')
-                    doc = Docs.Create.VideoDocument(data, { title: title, _width: 400, _height: 315, transcript: transcript })
-                    break;
-                case "Webpage":
-                    console.log('create ', type, 'document')
-                    doc = Docs.Create.WebDocument(data, { title: title, text: text })
-                    break;
-                case "HTML":
-                    console.log('create ', type, 'document')
-                    doc = Docs.Create.WebDocument(data, { title: title, text: text })
-                    break;
-                case "Text":
-                    console.log('create ', type, 'document')
-                    doc = Docs.Create.TextDocument(data, { title: title, text: text })
-                    break;
-                case "PDF":
-                    console.log('create ', type, 'document')
-                    doc = Docs.Create.PdfDocument(data, { title: title, text: text })
-                    break;
-            }
-        }
-        if (doc !== null) NewLightboxView.SetNewLightboxDoc(doc)
-    }}>
-        {loading ? 
-        <div className={`image-container`}>
-        </div>
-        :
-        previewUrl ? <div className={`image-container`}>
-            {<img className={`image`} src={previewUrl}></img>}
-        </div>
-        : null
-        }
-        <div className={`title`}>{title}</div>
-        <div className={`info`}>
-            {!loading && <div className={`type-container`}>
-                <div className={`lb-label`}>Type</div><div className={`lb-type`}>{getType(type!)}</div>
-            </div>}
-            {!loading && <div className={`distance-container`}>
-                <div className={`lb-label`}>Distance</div><div className={`lb-distance`}>{distance}</div>
-            </div>}
-        </div>
-        <div className={`source`}>
-            {!loading && <div className={`source-container`}>
-                <div className={`lb-label`}>Source</div><div className={`lb-source`}>{source}</div>
-            </div>}
-        </div>
-        <div className={`explainer`}>
-            {!loading && 
-            <div>
-                You are seeing this recommendation because this document also explores
-                <div className={`concepts-container`}>
-                    {related_concepts?.map((val) => {
-                        return <div className={'concept'}>{val}</div>
-                    })}
-                </div>
-            </div>}
-        </div>
-        <div className={`hide-rec`}>
-            {!loading && <><div>Hide Recommendation</div><div style={{fontSize: 15, paddingRight: 5}}><FaEyeSlash/></div></>}
+    const { title, data, type, text, transcript, loading, source, previewUrl, related_concepts, distance, docId } = props;
+
+    return (
+        <div
+            className={`recommendation-container ${loading && 'loading'} ${previewUrl && 'previewUrl'}`}
+            onClick={() => {
+                let doc: Doc | null = null;
+                if (source == 'Dash' && docId) {
+                    const docView = DocumentManager.Instance.getDocumentViewsById(docId).lastElement();
+                    if (docView) {
+                        doc = docView.rootDoc;
+                    }
+                } else if (data) {
+                    console.log(data, type);
+                    switch (type) {
+                        case 'YouTube':
+                            console.log('create ', type, 'document');
+                            doc = Docs.Create.VideoDocument(data, { title: title, _width: 400, _height: 315, transcript: transcript });
+                            break;
+                        case 'Video':
+                            console.log('create ', type, 'document');
+                            doc = Docs.Create.VideoDocument(data, { title: title, _width: 400, _height: 315, transcript: transcript });
+                            break;
+                        case 'Webpage':
+                            console.log('create ', type, 'document');
+                            doc = Docs.Create.WebDocument(data, { title: title, text: text });
+                            break;
+                        case 'HTML':
+                            console.log('create ', type, 'document');
+                            doc = Docs.Create.WebDocument(data, { title: title, text: text });
+                            break;
+                        case 'Text':
+                            console.log('create ', type, 'document');
+                            doc = Docs.Create.TextDocument(data, { title: title, text: text });
+                            break;
+                        case 'PDF':
+                            console.log('create ', type, 'document');
+                            doc = Docs.Create.PdfDocument(data, { title: title, text: text });
+                            break;
+                    }
+                }
+                if (doc !== null) NewLightboxView.SetNewLightboxDoc(doc);
+            }}>
+            {loading ? <div className={`image-container`}></div> : previewUrl ? <div className={`image-container`}>{<img className={`image`} src={previewUrl}></img>}</div> : null}
+            <div className={`title`}>{title}</div>
+            <div className={`info`}>
+                {!loading && (
+                    <div className={`type-container`}>
+                        <div className={`lb-label`}>Type</div>
+                        <div className={`lb-type`}>{getType(type!)}</div>
+                    </div>
+                )}
+                {!loading && (
+                    <div className={`distance-container`}>
+                        <div className={`lb-label`}>Distance</div>
+                        <div className={`lb-distance`}>{distance}</div>
+                    </div>
+                )}
+            </div>
+            <div className={`source`}>
+                {!loading && (
+                    <div className={`source-container`}>
+                        <div className={`lb-label`}>Source</div>
+                        <div className={`lb-source`}>{source}</div>
+                    </div>
+                )}
+            </div>
+            <div className={`explainer`}>
+                {!loading && (
+                    <div>
+                        You are seeing this recommendation because this document also explores
+                        <div className={`concepts-container`}>
+                            {related_concepts?.map(val => {
+                                return <div className={'concept'}>{val}</div>;
+                            })}
+                        </div>
+                    </div>
+                )}
+            </div>
+            <div className={`hide-rec`}>
+                {!loading && (
+                    <>
+                        <div>Hide Recommendation</div>
+                        <div style={{ fontSize: 15, paddingRight: 5 }}>
+                            <FaEyeSlash />
+                        </div>
+                    </>
+                )}
+            </div>
         </div>
-    </div>
-}
\ No newline at end of file
+    );
+};
-- 
cgit v1.2.3-70-g09d2


From 4c8eee9811abd072d2a6adfe24eaf04f980ccf21 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 9 Aug 2023 15:21:20 -0400
Subject: updated file system to include recentlyClosed, Shared, and Dashboards
 and fixed drag drop to make sense for the filesystem.   Fixed loading
 documents to happen in one batch by fixing UPDATE_CACHED_DOCS to save only
 documents accessible from current dashboard.

---
 src/Utils.ts                                       |   2 +-
 src/client/DocServer.ts                            |  60 +-
 src/client/documents/DocumentTypes.ts              |   4 -
 src/client/documents/Documents.ts                  |  12 +-
 src/client/util/CurrentUserUtils.ts                |  37 +-
 src/client/util/DocumentManager.ts                 |   5 +-
 src/client/util/DragManager.ts                     |   4 +-
 src/client/util/GroupManager.tsx                   |   5 +-
 src/client/util/GroupMemberView.tsx                |   3 +-
 src/client/util/LinkManager.ts                     |   4 +-
 src/client/util/ReplayMovements.ts                 |   1 -
 src/client/util/ServerStats.tsx                    |  26 +-
 src/client/util/SettingsManager.tsx                |  11 +-
 src/client/util/SharingManager.tsx                 |  11 +-
 src/client/util/reportManager/ReportManager.tsx    |   5 +-
 src/client/views/DashboardView.tsx                 |  83 +--
 src/client/views/DocComponent.tsx                  |   4 +-
 src/client/views/FilterPanel.tsx                   |  18 +-
 src/client/views/LightboxView.tsx                  |   4 +-
 src/client/views/Main.tsx                          |   5 +-
 src/client/views/MainView.tsx                      |  12 +-
 src/client/views/PropertiesButtons.tsx             |   1 -
 src/client/views/PropertiesDocContextSelector.tsx  |   1 -
 src/client/views/PropertiesSection.tsx             |  80 ++-
 src/client/views/PropertiesView.tsx                | 758 ++++++++++-----------
 src/client/views/StyleProvider.tsx                 |   8 +-
 src/client/views/UndoStack.tsx                     |  43 +-
 .../views/collections/CollectionDockingView.tsx    |   7 +-
 src/client/views/collections/CollectionMenu.tsx    |   2 +-
 .../views/collections/CollectionStackingView.tsx   |   1 -
 .../views/collections/CollectionTreeView.tsx       |   1 +
 src/client/views/collections/TabDocView.tsx        |   2 +-
 src/client/views/collections/TreeView.tsx          |   2 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |   1 -
 src/client/views/global/globalScripts.ts           |   1 -
 .../views/newlightbox/ExploreView/ExploreView.tsx  |   3 -
 .../components/Recommendation/Recommendation.tsx   |   1 -
 src/client/views/nodes/DataVizBox/utils/D3Utils.ts |   1 -
 src/client/views/nodes/DocumentView.tsx            |   3 +-
 src/client/views/nodes/LinkDocPreview.tsx          |   2 +-
 src/client/views/nodes/MapBox/MapBox.tsx           |   1 -
 src/client/views/nodes/ScreenshotBox.tsx           |   5 +-
 src/client/views/nodes/ScriptingBox.tsx            |   2 -
 .../views/nodes/formattedText/FormattedTextBox.tsx |  20 +-
 .../views/nodes/formattedText/RichTextRules.ts     |  26 +-
 src/client/views/pdf/AnchorMenu.tsx                |   5 +-
 src/client/views/search/SearchBox.tsx              |  78 ++-
 src/client/views/topbar/TopBar.tsx                 |  38 +-
 src/fields/Doc.ts                                  |  81 ++-
 src/fields/FieldLoader.tsx                         |   5 +-
 src/server/DashUploadUtils.ts                      |   3 +-
 51 files changed, 727 insertions(+), 771 deletions(-)

(limited to 'src/client/views/newlightbox/ExploreView/ExploreView.tsx')

diff --git a/src/Utils.ts b/src/Utils.ts
index 8b9fe2aab..7f83ab8f5 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -76,7 +76,7 @@ export namespace Utils {
             });
             return returnedUri;
         } catch (e) {
-            console.log('VideoBox :' + e);
+            console.log('ConvertDataURI :' + e);
         }
     }
 
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index ad5a73598..40979d631 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -1,16 +1,18 @@
 import { runInAction } from 'mobx';
 import * as rp from 'request-promise';
 import * as io from 'socket.io-client';
-import { Doc, Opt } from '../fields/Doc';
+import { Doc, DocListCast, Opt } from '../fields/Doc';
 import { UpdatingFromServer } from '../fields/DocSymbols';
 import { FieldLoader } from '../fields/FieldLoader';
 import { HandleUpdate, Id, Parent } from '../fields/FieldSymbols';
 import { ObjectField } from '../fields/ObjectField';
 import { RefField } from '../fields/RefField';
-import { StrCast } from '../fields/Types';
+import { DocCast, StrCast } from '../fields/Types';
 import MobileInkOverlay from '../mobile/MobileInkOverlay';
 import { emptyFunction, Utils } from '../Utils';
 import { GestureContent, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, YoutubeQueryTypes } from './../server/Message';
+import { DocumentType } from './documents/DocumentTypes';
+import { LinkManager } from './util/LinkManager';
 import { SerializationHelper } from './util/SerializationHelper';
 import { GestureOverlay } from './views/GestureOverlay';
 
@@ -30,35 +32,44 @@ import { GestureOverlay } from './views/GestureOverlay';
 export namespace DocServer {
     let _cache: { [id: string]: RefField | Promise<Opt<RefField>> } = {};
 
-    export function QUERY_SERVER_CACHE(title: string) {
+    export function FindDocByTitle(title: string) {
         const foundDocId = Array.from(Object.keys(_cache))
             .filter(key => _cache[key] instanceof Doc)
             .find(key => (_cache[key] as Doc).title === title);
 
         return foundDocId ? (_cache[foundDocId] as Doc) : undefined;
     }
-    let lastCacheUpdate = 0;
-    export function UPDATE_SERVER_CACHE(print: boolean = false) {
-        if (print) {
-            const strings: string[] = [];
-            Array.from(Object.keys(_cache)).forEach(key => {
-                const doc = _cache[key];
-                if (doc instanceof Doc) strings.push(StrCast(doc.author) + ' ' + StrCast(doc.title) + ' ' + StrCast(Doc.GetT(doc, 'title', 'string', true)));
-            });
-            strings.sort().forEach((str, i) => console.log(i.toString() + ' ' + str));
-        }
-        const filtered = Array.from(Object.keys(_cache)).filter(key => {
-            const doc = _cache[key] as Doc;
-            return true;
-            if (!(StrCast(doc.author).includes('.edu') || StrCast(doc.author).includes('.com')) || doc.author === Doc.CurrentUserEmail) return true;
-            return false;
+    let cacheDocumentIds = ''; // ; separate string of all documents ids in the user's working set (cached on the server)
+    export let CacheNeedsUpdate = false;
+    export function UPDATE_SERVER_CACHE() {
+        const prototypes = Object.values(DocumentType)
+            .filter(type => type !== DocumentType.NONE)
+            .map(type => _cache[type + 'Proto'])
+            .filter(doc => doc instanceof Doc)
+            .map(doc => doc as Doc);
+        const references = new Set<Doc>(prototypes);
+        Doc.FindReferences(Doc.UserDoc(), references, undefined);
+        DocListCast(DocCast(Doc.UserDoc().myLinkDatabase).data).forEach(link => {
+            if (!references.has(DocCast(link.link_anchor_1)) && !references.has(DocCast(link.link_anchor_2))) {
+                Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myLinkDatabase), 'data', link);
+            }
         });
-        if (filtered.length === lastCacheUpdate) return;
-        lastCacheUpdate = filtered.length;
+        LinkManager.userLinkDBs.forEach(linkDb => Doc.FindReferences(linkDb, references, undefined));
+        const filtered = Array.from(references);
+
+        const newCacheUpdate = filtered.map(doc => doc[Id]).join(';');
+        if (newCacheUpdate === cacheDocumentIds) return;
+        cacheDocumentIds = newCacheUpdate;
+
+        // print out cached docs
+        console.log('Set cached docs = ');
+        const is_filtered = filtered.filter(doc => !Doc.IsSystem(doc));
+        const strings = is_filtered.map(doc => StrCast(doc.title) + ' ' + (Doc.IsDataProto(doc) ? '(data)' : '(embedding)'));
+        strings.sort().forEach((str, i) => console.log(i.toString() + ' ' + str));
 
         rp.post(Utils.prepend('/setCacheDocumentIds'), {
             body: {
-                cacheDocumentIds: filtered.join(';'),
+                cacheDocumentIds,
             },
             json: true,
         });
@@ -353,7 +364,7 @@ export namespace DocServer {
         // i) which documents need to be fetched
         // ii) which are already in the process of being fetched
         // iii) which already exist in the cache
-        for (const id of ids) {
+        for (const id of ids.filter(id => id)) {
             const cached = _cache[id];
             if (cached === undefined) {
                 defaultPromises.push({
@@ -382,7 +393,7 @@ export namespace DocServer {
             // fields for the given ids. This returns a promise, which, when resolved, indicates that all the JSON serialized versions of
             // the fields have been returned from the server
             console.log('Requesting ' + requestedIds.length);
-            FieldLoader.active && runInAction(() => (FieldLoader.ServerLoadStatus.requested = requestedIds.length));
+            setTimeout(() => runInAction(() => (FieldLoader.ServerLoadStatus.requested = requestedIds.length)));
             const serializedFields = await Utils.EmitCallback(_socket, MessageStore.GetRefFields, requestedIds);
 
             // 3) when the serialized RefFields have been received, go head and begin deserializing them into objects.
@@ -392,7 +403,7 @@ export namespace DocServer {
             console.log('deserializing ' + serializedFields.length + ' fields');
             for (const field of serializedFields) {
                 processed++;
-                if (FieldLoader.active && processed % 150 === 0) {
+                if (processed % 150 === 0) {
                     runInAction(() => (FieldLoader.ServerLoadStatus.retrieved = processed));
                     await new Promise(res => setTimeout(res)); // force loading to yield to splash screen rendering to update progress
                 }
@@ -478,6 +489,7 @@ export namespace DocServer {
      * @param field the [RefField] to be serialized and sent to the server to be stored in the database
      */
     export function CreateField(field: RefField) {
+        CacheNeedsUpdate = true;
         _CreateField(field);
     }
 
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index b629d9b8c..1d0ddce40 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -14,13 +14,11 @@ export enum DocumentType {
     INK = 'ink',
     SCREENSHOT = 'screenshot',
     FONTICON = 'fonticonbox',
-    FILTER = 'filter',
     SEARCH = 'search', // search query
     LABEL = 'label', // simple text label
     BUTTON = 'button', // onClick button
     WEBCAM = 'webcam', // webcam
     CONFIG = 'config', // configuration document intended to specify a view layout configuration, but not be directly rendered (e.g., for saving the page# of a PDF, or view transform of a collection)
-    DATE = 'date', // calendar view of a date
     SCRIPTING = 'script', // script editor
     EQUATION = 'equation', // equation editor
     FUNCPLOT = 'funcplot', // function plotter
@@ -31,14 +29,12 @@ export enum DocumentType {
 
     // special purpose wrappers that either take no data or are compositions of lower level types
     LINK = 'link',
-    LINKANCHOR = 'linkanchor',
     IMPORT = 'import',
     SLIDER = 'slider',
     PRES = 'presentation',
     PRESELEMENT = 'preselement',
     COLOR = 'color',
     YOUTUBE = 'youtube',
-    SEARCHITEM = 'searchitem',
     COMPARISON = 'comparison',
     GROUP = 'group',
 
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 8eeceaa15..fccad80ee 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1,5 +1,5 @@
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { action, runInAction } from 'mobx';
+import { action, reaction, runInAction } from 'mobx';
 import { basename } from 'path';
 import { DateField } from '../../fields/DateField';
 import { Doc, DocListCast, Field, Opt, updateCachedAcls } from '../../fields/Doc';
@@ -744,6 +744,10 @@ export namespace Docs {
                 // an entry dedicated to the given DocumentType)
                 target && PrototypeMap.set(type, target);
             });
+            reaction(
+                () => (proto => StrCast(proto?.BROADCAST_MESSAGE))(DocServer.GetCachedRefField('rtfProto') as Doc),
+                msg => msg && alert(msg)
+            );
         }
 
         /**
@@ -887,8 +891,6 @@ export namespace Docs {
                 DocUtils.MakeLinkToActiveAudio(() => viewDoc);
             }
 
-            Doc.AddFileOrphan(dataDoc);
-
             updateCachedAcls(dataDoc);
             updateCachedAcls(viewDoc);
 
@@ -1150,9 +1152,6 @@ export namespace Docs {
         export function FontIconDocument(options?: DocumentOptions) {
             return InstanceFromProto(Prototypes.get(DocumentType.FONTICON), undefined, { ...(options || {}) });
         }
-        export function FilterDocument(options?: DocumentOptions) {
-            return InstanceFromProto(Prototypes.get(DocumentType.FILTER), undefined, { ...(options || {}) });
-        }
 
         export function PresElementBoxDocument() {
             return Prototypes.get(DocumentType.PRESELEMENT);
@@ -1872,7 +1871,6 @@ export namespace DocUtils {
     export function copyDragFactory(dragFactory: Doc) {
         if (!dragFactory) return undefined;
         const ndoc = dragFactory.isTemplateDoc ? Doc.ApplyTemplate(dragFactory) : Doc.MakeCopy(dragFactory, true);
-        ndoc && Doc.AddFileOrphan(Doc.GetProto(ndoc));
         if (ndoc && dragFactory['dragFactory_count'] !== undefined) {
             dragFactory['dragFactory_count'] = NumCast(dragFactory['dragFactory_count']) + 1;
             Doc.SetInPlace(ndoc, 'title', ndoc.title + ' ' + NumCast(dragFactory['dragFactory_count']).toString(), true);
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 21bcec6d1..e8262ff3b 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -152,7 +152,7 @@ export class CurrentUserUtils {
             { noteType: "Idea", backgroundColor: "pink", icon: "lightbulb" },
             { noteType: "Topic", backgroundColor: "lightblue", icon: "book-open" }];
         const reqdNoteList = reqdTempOpts.map(opts => {
-            const reqdOpts = {...opts, title: "text", width:200, layout_autoHeight: true, layout_fitWidth: true};
+            const reqdOpts = {...opts, isSystem:true, title: "text", width:200, layout_autoHeight: true, layout_fitWidth: true};
             const noteType = tempNotes ? DocListCast(tempNotes.data).find(doc => doc.noteType === opts.noteType): undefined;
             return DocUtils.AssignOpts(noteType, reqdOpts) ?? MakeTemplate(Docs.Create.TextDocument("",reqdOpts), true, opts.noteType??"Note");
         });
@@ -339,7 +339,7 @@ export class CurrentUserUtils {
     }
 
     /// returns descriptions needed to buttons for the left sidebar to open up panes displaying different collections of documents
-    static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}}[] {
+    static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}, hidden?: boolean}[] {
       const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())"; 
       const getActiveDashTrails = "Doc.ActiveDashboard?.myTrails";
         return [
@@ -348,7 +348,7 @@ export class CurrentUserUtils {
             { title: "Files",           toolTip: "Files",           target: this.setupFilesystem(doc, "myFilesystem"),         ignoreClick: true, icon: "folder-open", },
             { title: "Tools",           toolTip: "Tools",           target: this.setupToolsBtnPanel(doc, "myTools"),           ignoreClick: true, icon: "wrench",      funcs: {hidden: "IsNoviceMode()"} },
             { title: "Imports",         toolTip: "Imports ⌘I",      target: this.setupImportSidebar(doc, "myImports"),         ignoreClick:false, icon: "upload",      },
-            { title: "Closed",          toolTip: "Recently Closed", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), ignoreClick: true, icon: "archive",     },
+            { title: "Closed",          toolTip: "Recently Closed", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), ignoreClick: true, icon: "archive",     hidden: true }, // this doc is hidden from the Sidebar, but it's still being used in MyFilesystem which ignores the hidden field
             { title: "Shared",          toolTip: "Shared Docs",     target: Doc.MySharedDocs,                                  ignoreClick: true, icon: "users",       funcs: {badgeValue: badgeValue}},
             { title: "Trails",          toolTip: "Trails ⌘R",       target: Doc.UserDoc(),                                     ignoreClick: true, icon: "pres-trail",  funcs: {target: getActiveDashTrails}},
             { title: "User Doc",        toolTip: "User Doc",        target: this.setupUserDocView(doc, "myUserDocView"),       ignoreClick: true, icon: "address-card",funcs: {hidden: "IsNoviceMode()"} },
@@ -357,17 +357,17 @@ export class CurrentUserUtils {
 
     /// the empty panel that is filled with whichever left menu button's panel has been selected
     static setupLeftSidebarPanel(doc: Doc, field="myLeftSidebarPanel") {
-        DocUtils.AssignDocField(doc, field, (opts) => Doc.assign(new Doc(), opts as any), {isSystem:true, undoIgnoreFields: new List<string>(['proto'])});
+        DocUtils.AssignDocField(doc, field, (opts) => Doc.assign(new Doc(), opts as any), {title:"leftSidebarPanel", isSystem:true, undoIgnoreFields: new List<string>(['proto'])});
     }
 
     /// Initializes the left sidebar menu buttons and the panels they open up
     static setupLeftSidebarMenu(doc: Doc, field="myLeftSidebarMenu") {
         this.setupLeftSidebarPanel(doc);
         const myLeftSidebarMenu = DocCast(doc[field]);
-        const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, toolTip, scripts, funcs }) => {
+        const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, toolTip, hidden, scripts, funcs }) => {
             const btnDoc = myLeftSidebarMenu ? DocListCast(myLeftSidebarMenu.data).find(doc => doc.title === title) : undefined;
             const reqdBtnOpts:DocumentOptions = {
-                title, icon, target, toolTip, btnType: ButtonType.MenuButton, isSystem: true, undoIgnoreFields: new List<string>(['height', 'data_columnHeaders']), dontRegisterView: true,
+                title, icon, target, toolTip, hidden, btnType: ButtonType.MenuButton, isSystem: true, undoIgnoreFields: new List<string>(['height', 'data_columnHeaders']), dontRegisterView: true,
                 _width: 60, _height: 60,  _dragOnlyWithinContainer: true, _layout_hideContextMenu: true,
             };
             return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), scripts, funcs);
@@ -495,7 +495,7 @@ export class CurrentUserUtils {
         const reqdOpts:DocumentOptions = {
             title: "My Dashboards", childHideLinkButton: true, treeViewFreezeChildren: "remove|add", treeViewHideTitle: true, layout_boxShadow: "0 0", childDontRegisterViews: true,
             dropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, isSystem: true,  treeViewTruncateTitleWidth: 350, ignoreClick: true, 
-            layout_headerButton: newDashboardButton, childDragAction: "embed",
+            layout_headerButton: newDashboardButton, childDragAction: "none",
             _layout_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true,
             contextMenuLabels:new List<string>(contextMenuLabels),
             contextMenuIcons:new List<string>(contextMenuIcons),
@@ -519,7 +519,6 @@ export class CurrentUserUtils {
     /// initializes the left sidebar File system pane
     static setupFilesystem(doc: Doc, field:string) {
         var myFilesystem = DocCast(doc[field]);
-        const myFileOrphans = DocUtils.AssignDocField(doc, "myFileOrphans", (opts) => Docs.Create.TreeDocument([], opts), { title: "Unfiled", undoIgnoreFields:new List<string>(['treeViewSortCriterion']), _dragOnlyWithinContainer: true, isSystem: true, isFolder: true });
         
         const newFolder = `TreeView_addNewFolder()`;
         const newFolderOpts: DocumentOptions = {
@@ -530,14 +529,15 @@ export class CurrentUserUtils {
         const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.layout_headerButton), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript);
         
         const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true, 
-            title: "My Documents", layout_headerButton: newFolderButton, treeViewHideTitle: true, dropAction: "proto", isSystem: true,
+            title: "My Documents", layout_headerButton: newFolderButton, treeViewHideTitle: true, dropAction: 'add', isSystem: true,
             isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, layout_boxShadow: "0 0", childDontRegisterViews: true, 
             treeViewTruncateTitleWidth: 350, ignoreClick: true, childDragAction: "embed",
             childContextMenuLabels: new List<string>(["Create new folder"]),
             childContextMenuIcons: new List<string>(["plus"]),
             layout_explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard."
         };
-        myFilesystem = DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, [myFileOrphans]);
+        const fileFolders = new Set(DocListCast(DocCast(doc[field])?.data));
+        myFilesystem = DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, Array.from(fileFolders));
         const childContextMenuScripts = [newFolder];
         if (Cast(myFilesystem.childContextMenuScripts, listSpec(ScriptField), null)?.length !== childContextMenuScripts.length) {
             myFilesystem.childContextMenuScripts = new List<ScriptField>(childContextMenuScripts.map(script => ScriptField.MakeFunction(script)!));
@@ -547,8 +547,8 @@ export class CurrentUserUtils {
 
     /// initializes the panel displaying docs that have been recently closed
     static setupRecentlyClosed(doc: Doc, field:string) {
-        const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, 
-            title: "My Recently Closed", childHideLinkButton: true, treeViewHideTitle: true, childDragAction: "embed", isSystem: true,
+        const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, isFolder: true,
+            title: "My Recently Closed", childHideLinkButton: true, treeViewHideTitle: true, childDragAction: "move", isSystem: true,
             treeViewTruncateTitleWidth: 350, ignoreClick: true,  layout_boxShadow: "0 0", childDontRegisterViews: true, dropAction: "same",
             contextMenuLabels: new List<string>(["Empty recently closed"]),
             contextMenuIcons:new List<string>(["trash"]),
@@ -562,8 +562,6 @@ export class CurrentUserUtils {
             toolTip: "Empty recently closed",};
         DocUtils.AssignDocField(recentlyClosed, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")});
 
-        //if (recentlyClosed.layout_headerButton !== clearDocsButton) Doc.GetProto(recentlyClosed).layout_headerButton = clearDocsButton;
-        
         if (!Cast(recentlyClosed.contextMenuScripts, listSpec(ScriptField),null)?.find((script) => script.script.originalScript === clearAll("self"))) {
             recentlyClosed.contextMenuScripts = new List<ScriptField>([ScriptField.MakeScript(clearAll("self"))!])
         }
@@ -777,6 +775,7 @@ export class CurrentUserUtils {
             const linkDocs = new Doc(linkDatabaseId, true);
             linkDocs.title = "LINK DATABASE: " + Doc.CurrentUserEmail;
             linkDocs.author = Doc.CurrentUserEmail;
+            linkDocs.isSystem = true;
             linkDocs.data = new List<Doc>([]);
             linkDocs["acl-Guest"] = SharingPermissions.Augment;
             doc.myLinkDatabase = new PrefetchProxy(linkDocs);
@@ -877,11 +876,13 @@ export class CurrentUserUtils {
         this.setupDockedButtons(doc);  // the bottom bar of font icons
         this.setupLeftSidebarMenu(doc); // the left-side column of buttons that open their contents in a flyout panel on the left
         this.setupDocTemplates(doc); // sets up the template menu of templates
-        this.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption
+        //this.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption
         DocUtils.AssignDocField(doc, "globalScriptDatabase", (opts) =>  Docs.Prototypes.MainScriptDocument(), {});
-        DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "header bar", isSystem: true, childDocumentsActive:false, dropAction: 'move'}); // drop down panel at top of dashboard for stashing documents
+        DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "My Header Bar", isSystem: true, childDocumentsActive:false, dropAction: 'move'}); // drop down panel at top of dashboard for stashing documents
         
+        Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyDashboards)
         Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MySharedDocs)
+        Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyRecentlyClosed)
 
         if (doc.activeDashboard instanceof Doc) {
             // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss)
@@ -889,7 +890,7 @@ export class CurrentUserUtils {
         }
         new LinkManager();
 
-        setTimeout(DocServer.UPDATE_SERVER_CACHE, 2500);
+        DocServer.CacheNeedsUpdate && setTimeout(DocServer.UPDATE_SERVER_CACHE, 2500);
         setInterval(DocServer.UPDATE_SERVER_CACHE, 120000);
         return doc;
     }
@@ -923,11 +924,9 @@ export class CurrentUserUtils {
                 {
                     const ids = result.cacheDocumentIds.split(";");
                     const batch = 30000;
-                    FieldLoader.active = true;
                     for (let i = 0; i < ids.length; i = Math.min(ids.length, i+batch)) {
                         await DocServer.GetRefFields(ids.slice(i, i+batch));
                     }
-                    FieldLoader.active = false;
                 }
                 return result;
             } else {
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 8e4e0d8f3..42132c2d7 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -75,7 +75,7 @@ export class DocumentManager {
 
     @action
     public AddView = (view: DocumentView) => {
-        //console.log("MOUNT " + view.props.Document.title + "/" + view.props.LayoutTemplateString);
+        if (view.props.LayoutTemplateString?.includes(KeyValueBox.name)) return;
         if (view.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) {
             const viewAnchorIndex = view.props.LayoutTemplateString.includes('link_anchor_2') ? 'link_anchor_2' : 'link_anchor_1';
             const link = view.rootDoc;
@@ -251,6 +251,7 @@ export class DocumentManager {
         options: DocFocusOptions, // options for how to navigate to target
         finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done.
     ) => {
+        Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, targetDoc);
         const docContextPath = DocumentManager.GetContextPath(targetDoc, true);
         if (docContextPath.some(doc => doc.hidden)) options.toggleTarget = false;
         let rootContextView =
@@ -335,7 +336,7 @@ export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCe
         if (dv && (!containingDoc || dv.props.docViewPath().lastElement()?.Document === containingDoc)) {
             DocumentManager.Instance.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.rootDoc));
         } else {
-            const container = DocCast(containingDoc ?? doc.embedContainer ?? doc);
+            const container = DocCast(containingDoc ?? doc.embedContainer ?? Doc.BestEmbedding(doc));
             const showDoc = !Doc.IsSystem(container) ? container : doc;
             options.toggleTarget = undefined;
             DocumentManager.Instance.showDocument(showDoc, options, () => DocumentManager.Instance.showDocument(doc, { ...options, openLocation: undefined })).then(() => {
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 85101fcab..f4ff38515 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -15,7 +15,7 @@ import { SelectionManager } from './SelectionManager';
 import { SnappingManager } from './SnappingManager';
 import { UndoManager } from './UndoManager';
 
-export type dropActionType = 'embed' | 'copy' | 'move' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove
+export type dropActionType = 'embed' | 'copy' | 'move' | 'add' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove
 
 /**
  * Initialize drag
@@ -213,6 +213,8 @@ export namespace DragManager {
                                 ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result)
                                 : docDragData.dropAction === 'embed'
                                 ? Doc.BestEmbedding(d)
+                                : docDragData.dropAction === 'add'
+                                ? d
                                 : docDragData.dropAction === 'proto'
                                 ? Doc.GetProto(d)
                                 : docDragData.dropAction === 'copy'
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index e406d89e7..f35844020 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -16,6 +16,7 @@ import { listSpec } from '../../fields/Schema';
 import { DateField } from '../../fields/DateField';
 import { Id } from '../../fields/FieldSymbols';
 import { Button, IconButton, Size, Type } from 'browndash-components';
+import { SettingsManager } from './SettingsManager';
 
 /**
  * Interface for options for the react-select component
@@ -281,7 +282,7 @@ export class GroupManager extends React.Component<{}> {
      */
     private get groupCreationModal() {
         const contents = (
-            <div className="group-create" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+            <div className="group-create" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
                 <div className="group-heading" style={{ marginBottom: 0 }}>
                     <p>
                         <b>New Group</b>
@@ -366,7 +367,7 @@ export class GroupManager extends React.Component<{}> {
         const groups = this.groupSort === 'ascending' ? this.allGroups.sort(sortGroups) : this.groupSort === 'descending' ? this.allGroups.sort(sortGroups).reverse() : this.allGroups;
 
         return (
-            <div className="group-interface" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+            <div className="group-interface" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
                 {this.groupCreationModal}
                 {this.currentGroup ? <GroupMemberView group={this.currentGroup} onCloseButtonClick={action(() => (this.currentGroup = undefined))} /> : null}
                 <div className="group-heading">
diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx
index 057f94f64..535d8ccc2 100644
--- a/src/client/util/GroupMemberView.tsx
+++ b/src/client/util/GroupMemberView.tsx
@@ -9,6 +9,7 @@ import { MainViewModal } from '../views/MainViewModal';
 import { GroupManager, UserOptions } from './GroupManager';
 import './GroupMemberView.scss';
 import { Button, IconButton, Size, Type } from 'browndash-components';
+import { SettingsManager } from './SettingsManager';
 
 interface GroupMemberViewProps {
     group: Doc;
@@ -28,7 +29,7 @@ export class GroupMemberView extends React.Component<GroupMemberViewProps> {
         const hasEditAccess = GroupManager.Instance.hasEditAccess(this.props.group);
 
         return !this.props.group ? null : (
-            <div className="editing-interface" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+            <div className="editing-interface" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
                 <div className="editing-header">
                     <input
                         className="group-title"
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index c7f092565..ef4b21b05 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -1,7 +1,8 @@
-import { action, observable, observe } from 'mobx';
+import { action, observable, observe, runInAction } from 'mobx';
 import { computedFn } from 'mobx-utils';
 import { Doc, DocListCast, DocListCastAsync, Field, Opt } from '../../fields/Doc';
 import { DirectLinks } from '../../fields/DocSymbols';
+import { FieldLoader } from '../../fields/FieldLoader';
 import { List } from '../../fields/List';
 import { ProxyField } from '../../fields/Proxy';
 import { Cast, DocCast, PromiseValue, StrCast } from '../../fields/Types';
@@ -132,6 +133,7 @@ export class LinkManager {
             },
             true
         );
+        runInAction(() => (FieldLoader.ServerLoadStatus.message = 'links'));
         LinkManager.addLinkDB(Doc.LinkDBDoc());
     }
 
diff --git a/src/client/util/ReplayMovements.ts b/src/client/util/ReplayMovements.ts
index cbc465d6a..d99630f82 100644
--- a/src/client/util/ReplayMovements.ts
+++ b/src/client/util/ReplayMovements.ts
@@ -187,7 +187,6 @@ export class ReplayMovements {
                 } else {
                     // tab wasn't open - open it and play the movement
                     const openedColFFView = this.openTab(movement.doc);
-                    console.log('openedColFFView', openedColFFView);
                     openedColFFView && this.zoomAndPan(movement, openedColFFView);
                 }
 
diff --git a/src/client/util/ServerStats.tsx b/src/client/util/ServerStats.tsx
index 6a6ec158e..3c7c35a7e 100644
--- a/src/client/util/ServerStats.tsx
+++ b/src/client/util/ServerStats.tsx
@@ -6,6 +6,7 @@ import './SharingManager.scss';
 import { PingManager } from './PingManager';
 import { StrCast } from '../../fields/Types';
 import { Doc } from '../../fields/Doc';
+import { SettingsManager } from './SettingsManager';
 
 @observer
 export class ServerStats extends React.Component<{}> {
@@ -42,21 +43,22 @@ export class ServerStats extends React.Component<{}> {
      */
     @computed get sharingInterface() {
         return (
-            <div style={{
-                display: "flex",
-                height: 300,
-                width: 400,
-                background: StrCast(Doc.UserDoc().userBackgroundColor),
-                opacity: 0.6}}>
-                    <div style={{width: 300,height: 100,margin: "auto",display: "flex",flexDirection: "column"}}>
-                        {PingManager.Instance.IsBeating ? 'The server connection is active' :
-                            'The server connection has been interrupted.NOTE: Any changes made will appear to persist but will be lost after a browser refreshes.'}
-                          
-                    <br/>
+            <div
+                style={{
+                    display: 'flex',
+                    height: 300,
+                    width: 400,
+                    background: SettingsManager.Instance?.userBackgroundColor,
+                    opacity: 0.6,
+                }}>
+                <div style={{ width: 300, height: 100, margin: 'auto', display: 'flex', flexDirection: 'column' }}>
+                    {PingManager.Instance.IsBeating ? 'The server connection is active' : 'The server connection has been interrupted.NOTE: Any changes made will appear to persist but will be lost after a browser refreshes.'}
+
+                    <br />
                     <span>Active users:{this._stats?.socketMap.length}</span>
                     {this._stats?.socketMap.map((user: any) => (
                         <p>{user.username}</p>
-                    ))}  
+                    ))}
                 </div>
             </div>
         );
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index b8e327968..573900825 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -1,10 +1,11 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Button, ColorPicker, Dropdown, DropdownType, EditableText, Group, NumberDropdown, Size, Toggle, ToggleType, Type } from 'browndash-components';
 import { action, computed, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { ColorState, SketchPicker } from 'react-color';
+import { BsGoogle } from 'react-icons/bs';
+import { FaFillDrip, FaPalette } from 'react-icons/fa';
 import { Doc } from '../../fields/Doc';
-import { Id } from '../../fields/FieldSymbols';
 import { BoolCast, Cast, StrCast } from '../../fields/Types';
 import { addStyleSheet, addStyleSheetRule, Utils } from '../../Utils';
 import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
@@ -12,13 +13,9 @@ import { DocServer } from '../DocServer';
 import { Networking } from '../Network';
 import { MainViewModal } from '../views/MainViewModal';
 import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
-import { DragManager } from './DragManager';
 import { GroupManager } from './GroupManager';
 import './SettingsManager.scss';
 import { undoBatch } from './UndoManager';
-import { Button, ColorPicker, Dropdown, DropdownType, EditableText, Group, NumberDropdown, Size, Toggle, ToggleType, Type } from 'browndash-components';
-import { BsGoogle } from 'react-icons/bs';
-import { FaFillDrip, FaPalette } from 'react-icons/fa';
 const higflyout = require('@hig/flyout');
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -39,6 +36,7 @@ export enum freeformScrollMode {
 
 @observer
 export class SettingsManager extends React.Component<{}> {
+    static Version = 'v0.5';
     public static Instance: SettingsManager;
     static _settingsStyle = addStyleSheet();
     @observable public isOpen = false;
@@ -452,6 +450,7 @@ export class SettingsManager extends React.Component<{}> {
                     </div>
 
                     <div className="settings-user">
+                        <div style={{ color: 'black' }}>{SettingsManager.Version}</div>
                         <div className="settings-username" style={{ color: this.userBackgroundColor }}>
                             {Doc.CurrentUserEmail}
                         </div>
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index cadcb1f8a..6171c01d7 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -8,6 +8,7 @@ import Select from 'react-select';
 import * as RequestPromise from 'request-promise';
 import { Doc, DocListCast, DocListCastAsync, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc';
 import { AclAdmin, AclPrivate, DocAcl, DocData } from '../../fields/DocSymbols';
+import { FieldLoader } from '../../fields/FieldLoader';
 import { Id } from '../../fields/FieldSymbols';
 import { StrCast } from '../../fields/Types';
 import { distributeAcls, GetEffectiveAcl, normalizeEmail, SharingPermissions, TraceMobx } from '../../fields/util';
@@ -23,6 +24,7 @@ import { GroupManager, UserOptions } from './GroupManager';
 import { GroupMemberView } from './GroupMemberView';
 import { LinkManager } from './LinkManager';
 import { SelectionManager } from './SelectionManager';
+import { SettingsManager } from './SettingsManager';
 import './SharingManager.scss';
 import { undoable } from './UndoManager';
 
@@ -136,6 +138,7 @@ export class SharingManager extends React.Component<{}> {
             this.populating = true;
             const userList = await RequestPromise.get(Utils.prepend('/getUsers'));
             const raw = (JSON.parse(userList) as User[]).filter(user => user.email !== 'guest' && user.email !== Doc.CurrentUserEmail);
+            runInAction(() => (FieldLoader.ServerLoadStatus.message = 'users'));
             const docs = await DocServer.GetRefFields(raw.reduce((list, user) => [...list, user.sharingDocumentId, user.linkDatabaseId], [] as string[]));
             raw.map(
                 action((newUser: User) => {
@@ -144,7 +147,7 @@ export class SharingManager extends React.Component<{}> {
                     if (sharingDoc instanceof Doc && linkDatabase instanceof Doc) {
                         if (!this.users.find(user => user.user.email === newUser.email)) {
                             this.users.push({ user: newUser, sharingDoc, linkDatabase, userColor: StrCast(sharingDoc.userColor) });
-                            LinkManager.addLinkDB(linkDatabase);
+                            //LinkManager.addLinkDB(linkDatabase);
                         }
                     }
                 })
@@ -525,10 +528,10 @@ export class SharingManager extends React.Component<{}> {
             const permissions = uniform ? StrCast(targetDoc?.[groupKey]) : '-multiple-';
 
             return !permissions ? null : (
-                <div key={groupKey} className={'container'} style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+                <div key={groupKey} className={'container'} style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
                     <div className={'padding'}>{StrCast(group.title)}</div>
                     &nbsp;
-                    {group instanceof Doc ? <IconButton icon={<FontAwesomeIcon icon={'info-circle'} />} size={Size.XSMALL} color={StrCast(Doc.UserDoc().userColor)} onClick={action(() => (GroupManager.Instance.currentGroup = group))} /> : null}
+                    {group instanceof Doc ? <IconButton icon={<FontAwesomeIcon icon={'info-circle'} />} size={Size.XSMALL} color={SettingsManager.Instance.userColor} onClick={action(() => (GroupManager.Instance.currentGroup = group))} /> : null}
                     <div className={'edit-actions'}>
                         {admin || this.myDocAcls ? (
                             <select className={`permissions-dropdown-${permissions}`} value={permissions} onChange={e => this.setInternalGroupSharing(group, e.currentTarget.value)}>
@@ -550,7 +553,7 @@ export class SharingManager extends React.Component<{}> {
                 <div
                     className="sharing-contents"
                     style={{
-                        background: StrCast(Doc.UserDoc().userBackgroundColor),
+                        background: SettingsManager.Instance.userBackgroundColor,
                         color: StrCast(Doc.UserDoc().userColor),
                     }}>
                     <p className="share-title" style={{ color: StrCast(Doc.UserDoc().userColor) }}>
diff --git a/src/client/util/reportManager/ReportManager.tsx b/src/client/util/reportManager/ReportManager.tsx
index e684bd637..7aad0f2b1 100644
--- a/src/client/util/reportManager/ReportManager.tsx
+++ b/src/client/util/reportManager/ReportManager.tsx
@@ -19,6 +19,7 @@ import { BugType, FileData, Priority, ReportForm, ViewState, bugDropdownItems, d
 import { Filter, FormInput, FormTextArea, IssueCard, IssueView, Tag } from './ReportManagerComponents';
 import { StrCast } from '../../../fields/Types';
 import { MdRefresh } from 'react-icons/md';
+import { SettingsManager } from '../SettingsManager';
 const higflyout = require('@hig/flyout');
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -213,11 +214,11 @@ export class ReportManager extends React.Component<{}> {
      * @returns the component that dispays all issues
      */
     private viewIssuesComponent = () => {
-        const darkMode = isDarkMode(StrCast(Doc.UserDoc().userBackgroundColor));
+        const darkMode = isDarkMode(SettingsManager.Instance.userBackgroundColor);
         const colors = darkMode ? darkColors : lightColors;
 
         return (
-            <div className="view-issues" style={{ backgroundColor: StrCast(Doc.UserDoc().userBackgroundColor), color: colors.text }}>
+            <div className="view-issues" style={{ backgroundColor: SettingsManager.Instance.userBackgroundColor, color: colors.text }}>
                 <div className="left" style={{ display: this.rightExpanded ? 'none' : 'flex' }}>
                     <div className="report-header">
                         <h2 style={{ color: colors.text }}>Open Issues</h2>
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index ae55c8ebf..21808d6e0 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -43,7 +43,7 @@ export class DashboardView extends React.Component {
     @observable private selectedDashboardGroup = DashboardGroup.MyDashboards;
 
     @observable private newDashboardName: string | undefined = undefined;
-    @observable private newDashboardColor: string | undefined = "#AFAFAF";
+    @observable private newDashboardColor: string | undefined = '#AFAFAF';
     @action abortCreateNewDashboard = () => {
         this.newDashboardName = undefined;
     };
@@ -100,30 +100,15 @@ export class DashboardView extends React.Component {
         const dashboardCount = DocListCast(Doc.MyDashboards.data).length + 1;
         const placeholder = `Dashboard ${dashboardCount}`;
         return (
-            <div className="new-dashboard"
-                style={{ 
+            <div
+                className="new-dashboard"
+                style={{
                     background: StrCast(Doc.UserDoc().userBackgroundColor),
-                    color: StrCast(Doc.UserDoc().userColor)
-                }}
-            >
+                    color: StrCast(Doc.UserDoc().userColor),
+                }}>
                 <div className="header">Create New Dashboard</div>
-                <EditableText 
-                    formLabel='Title'
-                    placeholder={placeholder}
-                    type={Type.SEC}
-                    color={StrCast(Doc.UserDoc().userColor)}
-                    setVal={val => this.setNewDashboardName(val as string)}
-                    fillWidth
-                />
-                <ColorPicker
-                    formLabel='Background'
-                    colorPickerType='github'
-                    type={Type.TERT}
-                    selectedColor={this.newDashboardColor}
-                    setSelectedColor={color => {
-                        this.setNewDashboardColor(color);
-                    }}
-                />
+                <EditableText formLabel="Title" placeholder={placeholder} type={Type.SEC} color={StrCast(Doc.UserDoc().userColor)} setVal={val => this.setNewDashboardName(val as string)} fillWidth />
+                <ColorPicker formLabel="Background" colorPickerType="github" type={Type.TERT} selectedColor={this.newDashboardColor} setSelectedColor={this.setNewDashboardColor} />
                 <div className="button-bar">
                     <Button text="Cancel" color={StrCast(Doc.UserDoc().userColor)} onClick={this.abortCreateNewDashboard} />
                     <Button type={Type.TERT} text="Create" color={StrCast(Doc.UserDoc().userVariantColor)} onClick={() => this.createNewDashboard(this.newDashboardName!, this.newDashboardColor)} />
@@ -165,21 +150,14 @@ export class DashboardView extends React.Component {
     };
 
     render() {
-        const color = StrCast(Doc.UserDoc().userColor)
-        const variant = StrCast(Doc.UserDoc().userVariantColor)
+        const color = StrCast(Doc.UserDoc().userColor);
+        const variant = StrCast(Doc.UserDoc().userVariantColor);
         return (
             <>
                 <div className="dashboard-view">
                     <div className="left-menu">
-                        <Button 
-                            text={'My Dashboards'}
-                            active={this.selectedDashboardGroup === DashboardGroup.MyDashboards}
-                            color={color}
-                            align={'flex-start'}
-                            onClick={() => this.selectDashboardGroup(DashboardGroup.MyDashboards)}
-                            fillWidth
-                        />
-                        <Button 
+                        <Button text={'My Dashboards'} active={this.selectedDashboardGroup === DashboardGroup.MyDashboards} color={color} align={'flex-start'} onClick={() => this.selectDashboardGroup(DashboardGroup.MyDashboards)} fillWidth />
+                        <Button
                             text={'Shared Dashboards' + ' (' + this.getDashboards(DashboardGroup.SharedDashboards).length + ')'}
                             active={this.selectedDashboardGroup === DashboardGroup.SharedDashboards}
                             color={this.getDashboards(DashboardGroup.SharedDashboards).some(dash => !DocListCast(Doc.MySharedDocs.viewed).includes(dash)) ? 'green' : color}
@@ -196,11 +174,11 @@ export class DashboardView extends React.Component {
                                 .filter(key => key !== `acl-${Doc.CurrentUserEmailNormalized}` && !['acl-Me', 'acl-Guest'].includes(key))
                                 .some(key => dashboard[DocAcl][key] !== AclPrivate);
                             return (
-                                <div 
-                                    className="dashboard-container" 
-                                    key={dashboard[Id]} 
+                                <div
+                                    className="dashboard-container"
+                                    key={dashboard[Id]}
                                     style={{ background: this.isUnviewedSharedDashboard(dashboard) && this.selectedDashboardGroup === DashboardGroup.SharedDashboards ? '#6CB982' : shared ? variant : '' }}
-                                    onContextMenu={e => this.onContextMenu(dashboard, e)} 
+                                    onContextMenu={e => this.onContextMenu(dashboard, e)}
                                     onClick={e => this.clickDashboard(e, dashboard)}>
                                     <img
                                         src={
@@ -208,12 +186,7 @@ export class DashboardView extends React.Component {
                                         }
                                     />
                                     <div className="info">
-                                        <EditableText 
-                                            type={Type.PRIM}
-                                            color={color}
-                                            val={StrCast(dashboard.title)} 
-                                            setVal={val => (Doc.GetProto(dashboard).title = val)}
-                                        />
+                                        <EditableText type={Type.PRIM} color={color} val={StrCast(dashboard.title)} setVal={val => (Doc.GetProto(dashboard).title = val)} />
                                         {this.selectedDashboardGroup === DashboardGroup.SharedDashboards && this.isUnviewedSharedDashboard(dashboard) ? <div>unviewed</div> : <div></div>}
                                         <div
                                             className="more"
@@ -229,10 +202,13 @@ export class DashboardView extends React.Component {
                                             <Button size={Size.SMALL} color={color} icon={<FontAwesomeIcon color={color} icon="bars" />} />
                                         </div>
                                     </div>
-                                    <div className={`background`} style={{
-                                        background: StrCast(Doc.UserDoc().userColor),
-                                        filter: 'opacity(0.2)'
-                                    }}/>
+                                    <div
+                                        className={`background`}
+                                        style={{
+                                            background: StrCast(Doc.UserDoc().userColor),
+                                            filter: 'opacity(0.2)',
+                                        }}
+                                    />
                                     <div className={'dashboard-status' + (shared ? '-shared' : '')}>{shared ? 'shared' : ''}</div>
                                 </div>
                             );
@@ -243,10 +219,13 @@ export class DashboardView extends React.Component {
                                 this.setNewDashboardName('');
                             }}>
                             +
-                            <div className={`background`} style={{
-                                background: StrCast(Doc.UserDoc().userColor),
-                                filter: 'opacity(0.2)'
-                            }}/>
+                            <div
+                                className={`background`}
+                                style={{
+                                    background: StrCast(Doc.UserDoc().userColor),
+                                    filter: 'opacity(0.2)',
+                                }}
+                            />
                         </div>
                     </div>
                 </div>
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 8fe5c2e01..e076e69ca 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -3,7 +3,7 @@ import { DateField } from '../../fields/DateField';
 import { Doc, DocListCast, HierarchyMapping, Opt, ReverseHierarchyMap } from '../../fields/Doc';
 import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, DocAcl, DocData } from '../../fields/DocSymbols';
 import { List } from '../../fields/List';
-import { Cast, StrCast } from '../../fields/Types';
+import { Cast, DocCast, StrCast } from '../../fields/Types';
 import { distributeAcls, GetEffectiveAcl, inheritParentAcls, SharingPermissions } from '../../fields/util';
 import { returnFalse } from '../../Utils';
 import { DocUtils } from '../documents/Documents';
@@ -149,9 +149,9 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
                 toRemove.forEach(doc => {
                     leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey);
                     Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
+                    Doc.RemoveDocFromList(Doc.GetProto(doc), 'proto_embeddings', doc);
                     doc.embedContainer = undefined;
                     if (recent) {
-                        Doc.RemoveDocFromList(recent, 'data', doc);
                         doc.type !== DocumentType.LOADING && Doc.AddDocToList(recent, 'data', doc, undefined, true, true);
                     }
                 });
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index 68d29942b..63bd01b19 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -169,8 +169,6 @@ export class FilterPanel extends React.Component<filterProps> {
 
     render() {
         const options = this._allFacets.filter(facet => this.currentFacets.indexOf(facet) === -1).map(facet => ({ value: facet, label: facet }));
-        console.log("this is option " + options)
-        console.log("this is alll facets " + this._allFacets)
         return (
             <div className="filterBox-treeView">
                 <div className="filterBox-select">
@@ -192,17 +190,15 @@ export class FilterPanel extends React.Component<filterProps> {
                 <div className="filterBox-tree" key="tree">
                     {Array.from(this.activeFacets.keys()).map(facetHeader => (
                         <div>
-                            <div className  = "filterBox-facetHeader">
-                                <div className = "filterBox-facetHeader-Header"> </div>
+                            <div className="filterBox-facetHeader">
+                                <div className="filterBox-facetHeader-Header"> </div>
                                 {facetHeader.charAt(0).toUpperCase() + facetHeader.slice(1)}
-                                
-                                <div className = "filterBox-facetHeader-collapse"> 
-                                 <AiOutlineMinusSquare/>
-                                 {/* <CiCircleRemove/> */}
-                                  </div>
-                               
+
+                                <div className="filterBox-facetHeader-collapse">
+                                    <AiOutlineMinusSquare />
+                                    {/* <CiCircleRemove/> */}
+                                </div>
                             </div>
-                           
 
                             {this.displayFacetValueFilterUIs(this.activeFacets.get(facetHeader), facetHeader)}
                         </div>
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index 286d39943..f79a30ad3 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -313,8 +313,10 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                     className="lightboxView-tabBtn"
                     title="open in tab"
                     onClick={e => {
+                        const lightdoc = LightboxView._docTarget || LightboxView._doc!;
                         e.stopPropagation();
-                        CollectionDockingView.AddSplit(LightboxView._docTarget || LightboxView._doc!, OpenWhereMod.none);
+                        Doc.RemoveDocFromList(Doc.MyRecentlyClosed, 'data', lightdoc);
+                        CollectionDockingView.AddSplit(lightdoc, OpenWhereMod.none);
                         SelectionManager.DeselectAll();
                         LightboxView.SetLightboxDoc(undefined);
                     }}>
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 2fa42d091..2a73d77ed 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -6,10 +6,7 @@ import * as React from 'react';
 import * as ReactDOM from 'react-dom/client';
 import { AssignAllExtensions } from '../../extensions/General/Extensions';
 import { FieldLoader } from '../../fields/FieldLoader';
-import { DocServer } from '../DocServer';
-import { Docs } from '../documents/Documents';
 import { CurrentUserUtils } from '../util/CurrentUserUtils';
-import { LinkManager } from '../util/LinkManager'; // this must come before importing Docs and CurrentUserUtils
 import { ReplayMovements } from '../util/ReplayMovements';
 import { TrackMovements } from '../util/TrackMovements';
 import { CollectionView } from './collections/CollectionView';
@@ -20,7 +17,7 @@ import './global/globalScripts';
 dotenv.config();
 
 AssignAllExtensions();
-FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0 }; // bcz: not sure why this is needed to get the code loaded properly...
+FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' }; // bcz: not sure why this is needed to get the code loaded properly...
 
 (async () => {
     MainView.Live = window.location.search.includes('live');
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index cbaa763f5..dc236b603 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -4,7 +4,7 @@ import * as far from '@fortawesome/free-regular-svg-icons';
 import * as fa from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import 'browndash-components/dist/styles/global.min.css';
-import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
+import { action, computed, configure, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import 'normalize.css';
 import * as React from 'react';
@@ -182,14 +182,6 @@ export class MainView extends React.Component {
                 'currentFrame',
             ]); // can play with these fields on someone else's
         }
-        DocServer.GetRefField('rtfProto').then(
-            proto =>
-                proto instanceof Doc &&
-                reaction(
-                    () => StrCast(proto.BROADCAST_MESSAGE),
-                    msg => msg && alert(msg)
-                )
-        );
 
         const tag = document.createElement('script');
         tag.src = 'https://www.youtube.com/iframe_api';
@@ -527,7 +519,7 @@ export class MainView extends React.Component {
     });
 
     initEventListeners = () => {
-        window.addEventListener('beforeunload', () => DocServer.UPDATE_SERVER_CACHE());
+        window.addEventListener('beforeunload', DocServer.UPDATE_SERVER_CACHE);
         window.addEventListener('drop', e => e.preventDefault(), false); // prevent default behavior of navigating to a new web page
         window.addEventListener('dragover', e => e.preventDefault(), false);
         // document.addEventListener("pointermove", action(e => SearchBox.Instance._undoBackground = UndoManager.batchCounter ? "#000000a8" : undefined));
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index b74eabcc3..8cae34d7d 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -375,7 +375,6 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                 val: value[1],
             };
         });
-        console.log('click val: ', this.onClickVal);
         return !this.selectedDoc ? null : (
             <Dropdown
                 tooltip={'Choose onClick behavior'}
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index 395aa2b61..d157e7b1c 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -38,7 +38,6 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
                 }, new Set<Doc>())
                 .keys()
         );
-        console.log('embeddings ' + embeddings.length);
 
         return doclayouts
             .filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance?.props.Document))
diff --git a/src/client/views/PropertiesSection.tsx b/src/client/views/PropertiesSection.tsx
index ec8043ffe..6fab0168b 100644
--- a/src/client/views/PropertiesSection.tsx
+++ b/src/client/views/PropertiesSection.tsx
@@ -1,19 +1,19 @@
 import React = require('react');
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
-import { action, computed, observable } from "mobx"
-import { observer } from "mobx-react"
-import './PropertiesSection.scss'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, observable } from 'mobx';
+import { observer } from 'mobx-react';
+import './PropertiesSection.scss';
 import { Doc } from '../../fields/Doc';
 import { StrCast } from '../../fields/Types';
 
 export interface PropertiesSectionProps {
-    title: string, 
-    content?: JSX.Element | string | null, 
-    isOpen: boolean,
-    setIsOpen: (bool: boolean) => any 
-    inSection?: boolean,
-    setInSection?: (bool: boolean) => any
-    onDoubleClick?: () => void
+    title: string;
+    content?: JSX.Element | string | null;
+    isOpen: boolean;
+    setIsOpen: (bool: boolean) => any;
+    inSection?: boolean;
+    setInSection?: (bool: boolean) => any;
+    onDoubleClick?: () => void;
 }
 
 @observer
@@ -33,34 +33,32 @@ export class PropertiesSection extends React.Component<PropertiesSectionProps> {
     @observable isDouble: boolean = false;
 
     render() {
-        console.log(this.props.title, this.props.content)
-        if (this.props.content === undefined || this.props.content === null) return null
-        else return <div className="propertiesView-section" onPointerEnter={action(() => (this.props.setInSection && this.props.setInSection(true)))} onPointerLeave={action(() => (this.props.setInSection && this.props.setInSection(false)))}>
-        <div className="propertiesView-sectionTitle" 
-            onDoubleClick={action((e) => {
-                this.isDouble = true;
-                this.props.onDoubleClick && this.props.onDoubleClick()
-                console.log("open options")
-                this.props.setIsOpen(true)
-                setTimeout(() => this.isDouble = false, 300)
-            })}
-            onClick={action((e) => {
-                this.props.setIsOpen(!this.props.isOpen)
-            })} 
-            style={{ 
-                background: this.props.isOpen ?  this.variantColor : this.backgroundColor,
-                color: this.color
-            }}>
-            {this.props.title}
-            <div className="propertiesView-sectionTitle-icon">
-                <FontAwesomeIcon icon={this.props.isOpen ? 'caret-down' : 'caret-right'} size="lg"  />
-            </div>
-        </div>
-        {!this.props.isOpen ? null :
-            <div className="propertiesView-content">
-                {this.props.content}
-            </div>
-        }
-    </div>
+        if (this.props.content === undefined || this.props.content === null) return null;
+        else
+            return (
+                <div className="propertiesView-section" onPointerEnter={action(() => this.props.setInSection && this.props.setInSection(true))} onPointerLeave={action(() => this.props.setInSection && this.props.setInSection(false))}>
+                    <div
+                        className="propertiesView-sectionTitle"
+                        onDoubleClick={action(e => {
+                            this.isDouble = true;
+                            this.props.onDoubleClick && this.props.onDoubleClick();
+                            this.props.setIsOpen(true);
+                            setTimeout(() => (this.isDouble = false), 300);
+                        })}
+                        onClick={action(e => {
+                            this.props.setIsOpen(!this.props.isOpen);
+                        })}
+                        style={{
+                            background: this.props.isOpen ? this.variantColor : this.backgroundColor,
+                            color: this.color,
+                        }}>
+                        {this.props.title}
+                        <div className="propertiesView-sectionTitle-icon">
+                            <FontAwesomeIcon icon={this.props.isOpen ? 'caret-down' : 'caret-right'} size="lg" />
+                        </div>
+                    </div>
+                    {!this.props.isOpen ? null : <div className="propertiesView-content">{this.props.content}</div>}
+                </div>
+            );
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 27b9c3c7a..872f1c6ab 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -8,7 +8,7 @@ import { concat } from 'lodash';
 import { Lambda, action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { ColorState, SketchPicker } from 'react-color';
-import * as Icons from "react-icons/bs"; //{BsCollectionFill, BsFillFileEarmarkImageFill} from "react-icons/bs"
+import * as Icons from 'react-icons/bs'; //{BsCollectionFill, BsFillFileEarmarkImageFill} from "react-icons/bs"
 import { GrCircleInformation } from 'react-icons/gr';
 import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents } from '../../Utils';
 import { Doc, DocListCast, Field, FieldResult, HierarchyMapping, NumListCast, Opt, ReverseHierarchyMap, StrListCast } from '../../fields/Doc';
@@ -51,7 +51,6 @@ interface PropertiesViewProps {
     addDocTab: (doc: Doc, where: OpenWhere) => boolean;
 }
 
-
 @observer
 export class PropertiesView extends React.Component<PropertiesViewProps> {
     private _widthUndo?: UndoManager.Batch;
@@ -191,7 +190,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             });
 
             rows.push(
-                <div className="propertiesView-field" key="newKeyValue" style={{ marginTop: '3px', backgroundColor: "white", textAlign: "center" }}>
+                <div className="propertiesView-field" key="newKeyValue" style={{ marginTop: '3px', backgroundColor: 'white', textAlign: 'center' }}>
                     <EditableView key="editableView" oneLine contents={'add key:value or #tags'} height={13} fontSize={10} GetValue={() => ''} SetValue={this.setKeyValue} />
                 </div>
             );
@@ -249,14 +248,12 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return !this.selectedDoc ? null : <PropertiesDocContextSelector DocView={this.selectedDocumentView} hideTitle={true} addDocTab={this.props.addDocTab} />;
     }
 
-    @computed get contextCount(){
-        console.log("in context count");
-        if (this.selectedDocumentView){ 
-            const target = (this.selectedDocumentView.props.Document)
-            const embeddings = DocListCast(target.proto_embeddings)
-            console.log(embeddings.length -1 );
-            return (embeddings.length - 1)
-        } else{
+    @computed get contextCount() {
+        if (this.selectedDocumentView) {
+            const target = this.selectedDocumentView.props.Document;
+            const embeddings = DocListCast(target.proto_embeddings);
+            return embeddings.length - 1;
+        } else {
             return 0;
         }
     }
@@ -266,13 +263,11 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return !selAnchor ? null : <PropertiesDocBacklinksSelector Document={selAnchor} hideTitle={true} addDocTab={this.props.addDocTab} />;
     }
 
-    @computed get linkCount(){
-        const selAnchor =  this.selectedDocumentView?.anchorViewDoc ?? LinkManager.currentLinkAnchor ?? this.selectedDoc;
+    @computed get linkCount() {
+        const selAnchor = this.selectedDocumentView?.anchorViewDoc ?? LinkManager.currentLinkAnchor ?? this.selectedDoc;
         var counter = 0;
 
-        LinkManager.Links(selAnchor).forEach((l, i) =>
-                counter ++
-            );
+        LinkManager.Links(selAnchor).forEach((l, i) => counter++);
 
         return counter;
     }
@@ -356,7 +351,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return (
             <Tooltip title={<div className="dash-tooltip">Notify with message</div>}>
                 <div className="notify-button">
-                    <FontAwesomeIcon className="notify-button-icon" icon="bell"  size="sm" />
+                    <FontAwesomeIcon className="notify-button-icon" icon="bell" size="sm" />
                 </div>
             </Tooltip>
         );
@@ -367,16 +362,16 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
      */
     @computed get expansionIcon() {
         return (
-            <div className="expansion-button" >
-                <IconButton 
-                    icon={<FontAwesomeIcon icon={'ellipsis-h'} />} 
-                    size={Size.XSMALL} 
-                    color={StrCast(Doc.UserDoc().userColor)} 
+            <div className="expansion-button">
+                <IconButton
+                    icon={<FontAwesomeIcon icon={'ellipsis-h'} />}
+                    size={Size.XSMALL}
+                    color={StrCast(Doc.UserDoc().userColor)}
                     onClick={action(() => {
                         if (this.selectedDocumentView || this.selectedDoc) {
                             SharingManager.Instance.open(this.selectedDocumentView?.props.Document === this.selectedDoc ? this.selectedDocumentView : undefined, this.selectedDoc);
                         }
-                    })} 
+                    })}
                 />
             </div>
         );
@@ -418,7 +413,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             <div>
                 <div className={'propertiesView-shareDropDown'}>
                     <div className={`propertiesView-shareDropDown${permission}`}>
-                        <div >{admin && permission !== 'Owner' ? this.getPermissionsSelect(name, permission, showGuestOptions) : concat(shareImage, ' ', permission)}</div>
+                        <div>{admin && permission !== 'Owner' ? this.getPermissionsSelect(name, permission, showGuestOptions) : concat(shareImage, ' ', permission)}</div>
                     </div>
                 </div>
             </div>
@@ -450,7 +445,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         const target = docs[0];
 
         const showAdmin = GetEffectiveAcl(target) == AclAdmin;
-        console.log(GetEffectiveAcl(target), Doc.GetProto(target)[`acl-${normalizeEmail(Doc.CurrentUserEmail)}`])
         const individualTableEntries = [];
         const usersAdded: string[] = []; // all shared users being added - organized by denormalized email
 
@@ -522,7 +516,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 <div>
                     <br></br> Individuals with Access to this Document
                 </div>
-                <div className="propertiesView-sharingTable" style={{background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor)}}>
+                <div className="propertiesView-sharingTable" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
                     {<div> {individualTableEntries}</div>}
                 </div>
                 {groupTableEntries.length > 0 ? (
@@ -530,7 +524,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         <div>
                             <br></br> Groups with Access to this Document
                         </div>
-                        <div className="propertiesView-sharingTable" style={{background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor)}}>
+                        <div className="propertiesView-sharingTable" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
                             {<div> {groupTableEntries}</div>}
                         </div>
                     </div>
@@ -562,68 +556,43 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     @computed get editableTitle() {
-
         const titles = new Set<string>();
         const title = Array.from(titles.keys()).length > 1 ? '--multiple selected--' : StrCast(this.selectedDoc?.title);
         SelectionManager.Views().forEach(dv => titles.add(StrCast(dv.rootDoc.title)));
-        return (
-            <EditableText
-                val={title}
-                setVal={this.setTitle}
-                color={this.color}
-                type={Type.SEC}
-                formLabel={"Title"}
-                fillWidth
-            />
-        );
+        return <EditableText val={title} setVal={this.setTitle} color={this.color} type={Type.SEC} formLabel={'Title'} fillWidth />;
     }
 
     @computed get currentType() {
-        // console.log("current type " + this.selectedDoc?.type)
- 
-         const documentType = StrCast(this.selectedDoc?.type)
-         var currentType: string = documentType;
-         var capitalizedDocType = Utils.cleanDocumentType(currentType as DocumentType);
- 
-         return (
-             <div>
-                 <div className = "propertiesView-wordType">Type</div>  
-                 <div className= "currentType"> 
-                 <div className='currentType-icon'>
-                      {this.currentComponent}
-                 </div>
-                
-                   {capitalizedDocType} 
-                
-                 </div>
-                
-             </div>
-           
-         )
-     }
+        const documentType = StrCast(this.selectedDoc?.type);
+        var currentType: string = documentType;
+        var capitalizedDocType = Utils.cleanDocumentType(currentType as DocumentType);
 
-    @computed get currentComponent() {
+        return (
+            <div>
+                <div className="propertiesView-wordType">Type</div>
+                <div className="currentType">
+                    <div className="currentType-icon">{this.currentComponent}</div>
 
-        var iconName = StrCast(this.selectedDoc?.systemIcon)
+                    {capitalizedDocType}
+                </div>
+            </div>
+        );
+    }
 
-        // if (this.selectedDoc?.type === DocumentType.COL){
-        //     console.log("i did it!")
-        // }
-       
+    @computed get currentComponent() {
+        var iconName = StrCast(this.selectedDoc?.systemIcon);
 
-        if (iconName){
+        if (iconName) {
             const Icon = Icons[iconName as keyof typeof Icons];
             return <Icon />;
-        } else{
-          return <Icons.BsFillCollectionFill/>
-
+        } else {
+            return <Icons.BsFillCollectionFill />;
         }
     }
 
     @undoBatch
     @action
     setTitle = (value: string | number) => {
-        console.log(value)
         if (SelectionManager.Views().length > 1) {
             SelectionManager.Views().map(dv => Doc.SetInPlace(dv.rootDoc, 'title', value, true));
         } else if (this.dataDoc) {
@@ -687,7 +656,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         className="inking-button-points"
                         style={{ backgroundColor: InkStrokeProperties.Instance._controlButton ? 'black' : '' }}
                         onPointerDown={action(() => (InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton))}>
-                        <FontAwesomeIcon icon="bezier-curve"  size="lg" />
+                        <FontAwesomeIcon icon="bezier-curve" size="lg" />
                     </div>
                 </Tooltip>
             </div>
@@ -706,10 +675,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 <input className="inputBox-input" type="text" value={value} onChange={e => setter(e.target.value)} onKeyPress={e => e.stopPropagation()} />
                 <div className="inputBox-button">
                     <div className="inputBox-button-up" key="up2" onPointerDown={undoBatch(action(() => this.upDownButtons('up', key)))}>
-                        <FontAwesomeIcon icon="caret-up"  size="sm" />
+                        <FontAwesomeIcon icon="caret-up" size="sm" />
                     </div>
                     <div className="inputbox-Button-down" key="down2" onPointerDown={undoBatch(action(() => this.upDownButtons('down', key)))}>
-                        <FontAwesomeIcon icon="caret-down"  size="sm" />
+                        <FontAwesomeIcon icon="caret-down" size="sm" />
                     </div>
                 </div>
             </div>
@@ -963,10 +932,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 <input className="inputBox-input" type="text" value={value} onChange={e => setter(e.target.value)} />
                 <div className="inputBox-button">
                     <div className="inputBox-button-up" key="up2" onPointerDown={undoBatch(action(() => this.upDownButtons('up', key)))}>
-                        <FontAwesomeIcon icon="caret-up"  size="sm" />
+                        <FontAwesomeIcon icon="caret-up" size="sm" />
                     </div>
                     <div className="inputbox-Button-down" key="down2" onPointerDown={undoBatch(action(() => this.upDownButtons('down', key)))}>
-                        <FontAwesomeIcon icon="caret-down"  size="sm" />
+                        <FontAwesomeIcon icon="caret-down" size="sm" />
                     </div>
                 </div>
             </div>
@@ -983,7 +952,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         this.openSharing = false;
         this.openLayout = false;
         this.openFilters = false;
-    }
+    };
 
     @computed get widthAndDash() {
         return (
@@ -1065,64 +1034,45 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     getNumber = (label: string, unit: string, min: number, max: number, number: number, setNumber: any) => {
-        return <div>
-            <NumberInput
-                formLabel={label}
-                formLabelPlacement={'left'}
-                type={Type.SEC}
-                unit={unit}
-                fillWidth
-                color={this.color}
-                number={number}
-                setNumber={setNumber} 
-                min={min}
-                max={max}            
-            />
-            <Slider 
-                multithumb={false}
-                color={this.color}
-                size={Size.XSMALL} 
-                min={min} 
-                max={max}
-                unit={unit} 
-                number={number}
-                setNumber={setNumber}
-                fillWidth
-            />
-        </div>
-    }
+        return (
+            <div>
+                <NumberInput formLabel={label} formLabelPlacement={'left'} type={Type.SEC} unit={unit} fillWidth color={this.color} number={number} setNumber={setNumber} min={min} max={max} />
+                <Slider multithumb={false} color={this.color} size={Size.XSMALL} min={min} max={max} unit={unit} number={number} setNumber={setNumber} fillWidth />
+            </div>
+        );
+    };
 
     @computed get transformEditor() {
         return (
             <div className="transform-editor">
                 {this.isInk ? this.controlPointsButton : null}
                 {this.getNumber(
-                    "Height",
-                    " px",
+                    'Height',
+                    ' px',
                     0,
                     1000,
                     Number(this.shapeHgt),
                     undoable((val: string) => !isNaN(Number(val)) && (this.shapeHgt = val), 'set height')
                 )}
                 {this.getNumber(
-                    "Width",
-                    " px",
+                    'Width',
+                    ' px',
                     0,
                     1000,
                     Number(this.shapeWid),
                     undoable((val: string) => !isNaN(Number(val)) && (this.shapeWid = val), 'set width')
                 )}
                 {this.getNumber(
-                    "X Coordinate",
-                    " px",
+                    'X Coordinate',
+                    ' px',
                     -2000,
                     2000,
                     Number(this.shapeXps),
                     undoable((val: string) => !isNaN(Number(val)) && (this.shapeXps = val), 'set x coord')
                 )}
                 {this.getNumber(
-                    "Y Coordinate",
-                    " px",
+                    'Y Coordinate',
+                    ' px',
                     -2000,
                     2000,
                     Number(this.shapeYps),
@@ -1133,38 +1083,44 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     @computed get optionsSubMenu() {
-        return <PropertiesSection
-            title="Options"
-            content={<PropertiesButtons />}
-            inSection={this.inOptions}
-            isOpen={this.openOptions}
-            setInSection={(bool) => this.inOptions = bool}
-            setIsOpen={(bool) => this.openOptions = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+        return (
+            <PropertiesSection
+                title="Options"
+                content={<PropertiesButtons />}
+                inSection={this.inOptions}
+                isOpen={this.openOptions}
+                setInSection={bool => (this.inOptions = bool)}
+                setIsOpen={bool => (this.openOptions = bool)}
+                onDoubleClick={() => this.onDoubleClick()}
+            />
+        );
     }
 
     @computed get sharingSubMenu() {
-        return <PropertiesSection
-            title="Sharing & Permissions"
-            content={<>
-            {/* <div className="propertiesView-buttonContainer"> */}
-                    <div className="propertiesView-acls-checkbox">
-                        Layout Permissions
-                        <Checkbox color="primary" onChange={action(() => (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} />
-                    </div>
-                    {/* <Tooltip title={<><div className="dash-tooltip">{"Re-distribute sharing settings"}</div></>}>
+        return (
+            <PropertiesSection
+                title="Sharing & Permissions"
+                content={
+                    <>
+                        {/* <div className="propertiesView-buttonContainer"> */}
+                        <div className="propertiesView-acls-checkbox">
+                            Layout Permissions
+                            <Checkbox color="primary" onChange={action(() => (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} />
+                        </div>
+                        {/* <Tooltip title={<><div className="dash-tooltip">{"Re-distribute sharing settings"}</div></>}>
                         <button onPointerDown={() => SharingManager.Instance.distributeOverCollection(this.selectedDoc!)}>
                             <FontAwesomeIcon icon="redo-alt"  size="1x" />
                         </button>
                     </Tooltip> */}
-                {/* </div> */}
-                {this.sharingTable}
-            </>}
-            isOpen={this.openSharing}
-            setIsOpen={(bool) => this.openSharing = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+                        {/* </div> */}
+                        {this.sharingTable}
+                    </>
+                }
+                isOpen={this.openSharing}
+                setIsOpen={bool => (this.openSharing = bool)}
+                onDoubleClick={() => this.onDoubleClick()}
+            />
+        );
     }
 
     /**
@@ -1192,15 +1148,19 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     };
 
     @computed get filtersSubMenu() {
-        return <PropertiesSection 
-            title="Filters"
-            content={<div className="propertiesView-content filters" style={{ position: 'relative', height: 'auto' }}>
-                <FilterPanel rootDoc={this.selectedDoc ?? Doc.ActiveDashboard!} />
-            </div>}
-            isOpen={this.openFilters}
-            setIsOpen={(bool) => this.openFilters = bool}
-             onDoubleClick={() => this.onDoubleClick()}
-        />
+        return (
+            <PropertiesSection
+                title="Filters"
+                content={
+                    <div className="propertiesView-content filters" style={{ position: 'relative', height: 'auto' }}>
+                        <FilterPanel rootDoc={this.selectedDoc ?? Doc.ActiveDashboard!} />
+                    </div>
+                }
+                isOpen={this.openFilters}
+                setIsOpen={bool => (this.openFilters = bool)}
+                onDoubleClick={() => this.onDoubleClick()}
+            />
+        );
     }
 
     @computed get inkSubMenu() {
@@ -1208,68 +1168,42 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
         return (
             <>
-                <PropertiesSection
-                    title="Appearance"
-                    content={this.isInk ? this.appearanceEditor : null}
-                    isOpen={this.openAppearance}
-                    setIsOpen={(bool) => this.openAppearance = bool}
-                     onDoubleClick={() => this.onDoubleClick()}
-                />
-                <PropertiesSection
-                    title="Transform"
-                    content={this.transformEditor}
-                    isOpen={this.openTransform}
-                    setIsOpen={(bool) => this.openTransform = bool}
-                    onDoubleClick={() => this.onDoubleClick()}
-                />
+                <PropertiesSection title="Appearance" content={this.isInk ? this.appearanceEditor : null} isOpen={this.openAppearance} setIsOpen={bool => (this.openAppearance = bool)} onDoubleClick={() => this.onDoubleClick()} />
+                <PropertiesSection title="Transform" content={this.transformEditor} isOpen={this.openTransform} setIsOpen={bool => (this.openTransform = bool)} onDoubleClick={() => this.onDoubleClick()} />
             </>
         );
     }
 
     @computed get fieldsSubMenu() {
-        return <PropertiesSection
-            title="Fields & Tags"
-            content={<div className="propertiesView-content fields">{
-                Doc.noviceMode ? this.noviceFields : this.expandedField}
-            </div>}
-            isOpen={this.openFields}
-            setIsOpen={(bool) => this.openFields = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+        return (
+            <PropertiesSection
+                title="Fields & Tags"
+                content={<div className="propertiesView-content fields">{Doc.noviceMode ? this.noviceFields : this.expandedField}</div>}
+                isOpen={this.openFields}
+                setIsOpen={bool => (this.openFields = bool)}
+                onDoubleClick={() => this.onDoubleClick()}
+            />
+        );
     }
 
     @computed get contextsSubMenu() {
-        return <PropertiesSection
-            title="Other Contexts"
-            content={this.contextCount > 0 ? this.contexts : "There are no other contexts."}
-            isOpen={this.openContexts}
-            setIsOpen={(bool) => this.openContexts = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+        return (
+            <PropertiesSection
+                title="Other Contexts"
+                content={this.contextCount > 0 ? this.contexts : 'There are no other contexts.'}
+                isOpen={this.openContexts}
+                setIsOpen={bool => (this.openContexts = bool)}
+                onDoubleClick={() => this.onDoubleClick()}
+            />
+        );
     }
 
-
-
-
-
     @computed get linksSubMenu() {
-        return <PropertiesSection
-            title="Linked To"
-            content={this.linkCount > 0 ? this.links : "There are no current links." }
-            isOpen={this.openLinks}
-            setIsOpen={(bool) => this.openLinks = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+        return <PropertiesSection title="Linked To" content={this.linkCount > 0 ? this.links : 'There are no current links.'} isOpen={this.openLinks} setIsOpen={bool => (this.openLinks = bool)} onDoubleClick={() => this.onDoubleClick()} />;
     }
 
     @computed get layoutSubMenu() {
-        return <PropertiesSection
-            title="Layout"
-            content={this.layoutPreview}
-            isOpen={this.openLayout}
-            setIsOpen={(bool) => this.openLayout = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+        return <PropertiesSection title="Layout" content={this.layoutPreview} isOpen={this.openLayout} setIsOpen={bool => (this.openLayout = bool)} onDoubleClick={() => this.onDoubleClick()} />;
     }
 
     @computed get description() {
@@ -1470,224 +1404,226 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         if (scale > 1) scale = 1;
         this.sourceAnchor && (this.sourceAnchor.followLinkZoomScale = scale);
     };
-    
+
     @computed get linkProperties() {
         const zoom = Number((NumCast(this.sourceAnchor?.followLinkZoomScale, 1) * 100).toPrecision(3));
         const targZoom = this.sourceAnchor?.followLinkZoom;
         const indent = 30;
         const hasSelectedAnchor = LinkManager.Links(this.sourceAnchor).includes(LinkManager.currentLink!);
 
-        return <>
-        <div className="propertiesView-section" style={{ background: 'darkgray' }}>
-            <div className="propertiesView-input first" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
-                <p>Relationship</p>
-                {this.editRelationship}
-            </div>
-            <div className="propertiesView-input" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
-                <p>Description</p>
-                {this.editDescription}
-            </div>
-            <div className="propertiesView-input inline">
-                <p>Show link</p>
-                <button
-                    style={{ background: !LinkManager.currentLink?.link_displayLine ? '' : '#4476f7', borderRadius: 3 }}
-                    onPointerDown={e => this.toggleLinkProp(e, 'link_displayLine')}
-                    onClick={e => e.stopPropagation()}
-                    className="propertiesButton">
-                    <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
-                </button>
-            </div>
-            <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
-                <p>Auto-move anchors</p>
-                <button
-                    style={{ background: !LinkManager.currentLink?.link_autoMoveAnchors ? '' : '#4476f7', borderRadius: 3 }}
-                    onPointerDown={e => this.toggleLinkProp(e, 'link_autoMoveAnchors')}
-                    onClick={e => e.stopPropagation()}
-                    className="propertiesButton">
-                    <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                </button>
-            </div>
-            <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
-                <p>Display arrow</p>
-                <button
-                    style={{ background: !LinkManager.currentLink?.link_displayArrow ? '' : '#4476f7', borderRadius: 3 }}
-                    onPointerDown={e => this.toggleLinkProp(e, 'link_displayArrow')}
-                    onClick={e => e.stopPropagation()}
-                    className="propertiesButton">
-                    <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
-                </button>
-            </div>
-        </div>
-        {!hasSelectedAnchor ? null : (
-            <div className="propertiesView-section">
-                <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 84px)' }}>
-                    <p>Follow by</p>
-                    <select onChange={e => this.changeFollowBehavior(e.currentTarget.value === 'Default' ? undefined : e.currentTarget.value)} value={Cast(this.sourceAnchor?.followLinkLocation, 'string', null)}>
-                        <option value={undefined}>Default</option>
-                        <option value={OpenWhere.addLeft}>Opening in new left pane</option>
-                        <option value={OpenWhere.addRight}>Opening in new right pane</option>
-                        <option value={OpenWhere.replaceLeft}>Replacing left tab</option>
-                        <option value={OpenWhere.replaceRight}>Replacing right tab</option>
-                        <option value={OpenWhere.lightbox}>Opening in lightbox</option>
-                        <option value={OpenWhere.add}>Opening in new tab</option>
-                        <option value={OpenWhere.replace}>Replacing current tab</option>
-                        <option value={OpenWhere.inParent}>Opening in same collection</option>
-                        {LinkManager.currentLink?.linksToAnnotation ? <option value="openExternal">Open in external page</option> : null}
-                    </select>
-                </div>
-                <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 134px) 50px' }}>
-                    <p>Animation</p>
-                    <select style={{ width: '100%', gridColumn: 2 }} onChange={e => this.changeAnimationBehavior(e.currentTarget.value)} value={StrCast(this.sourceAnchor?.followLinkAnimEffect, 'default')}>
-                        <option value="default">Default</option>
-                        {[PresEffect.None, PresEffect.Zoom, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => (
-                            <option key={effect.toString()} value={effect.toString()}>
-                                {effect.toString()}
-                            </option>
-                        ))}
-                    </select>
-                    <div className="effectDirection" style={{ marginLeft: '10px', display: 'grid', width: 40, height: 36, gridColumn: 3, gridTemplateRows: '12px 12px 12px' }}>
-                        {this.animationDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})}
-                        {this.animationDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})}
-                        {this.animationDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})}
-                        {this.animationDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})}
-                        {this.animationDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
+        return (
+            <>
+                <div className="propertiesView-section" style={{ background: 'darkgray' }}>
+                    <div className="propertiesView-input first" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
+                        <p>Relationship</p>
+                        {this.editRelationship}
+                    </div>
+                    <div className="propertiesView-input" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
+                        <p>Description</p>
+                        {this.editDescription}
+                    </div>
+                    <div className="propertiesView-input inline">
+                        <p>Show link</p>
+                        <button
+                            style={{ background: !LinkManager.currentLink?.link_displayLine ? '' : '#4476f7', borderRadius: 3 }}
+                            onPointerDown={e => this.toggleLinkProp(e, 'link_displayLine')}
+                            onClick={e => e.stopPropagation()}
+                            className="propertiesButton">
+                            <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
+                        </button>
+                    </div>
+                    <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
+                        <p>Auto-move anchors</p>
+                        <button
+                            style={{ background: !LinkManager.currentLink?.link_autoMoveAnchors ? '' : '#4476f7', borderRadius: 3 }}
+                            onPointerDown={e => this.toggleLinkProp(e, 'link_autoMoveAnchors')}
+                            onClick={e => e.stopPropagation()}
+                            className="propertiesButton">
+                            <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                        </button>
+                    </div>
+                    <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
+                        <p>Display arrow</p>
+                        <button
+                            style={{ background: !LinkManager.currentLink?.link_displayArrow ? '' : '#4476f7', borderRadius: 3 }}
+                            onPointerDown={e => this.toggleLinkProp(e, 'link_displayArrow')}
+                            onClick={e => e.stopPropagation()}
+                            className="propertiesButton">
+                            <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
+                        </button>
                     </div>
                 </div>
-                {PresBox.inputter(
-                    '0.1',
-                    '0.1',
-                    '10',
-                    NumCast(this.sourceAnchor?.followLinkTransitionTime) / 1000,
-                    true,
-                    (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => this.sourceAnchor && (this.sourceAnchor.followLinkTransitionTime = timeInMS)),
-                    indent
-                )}{' '}
-                <div
-                    className={'slider-headers'}
-                    style={{
-                        display: 'grid',
-                        justifyContent: 'space-between',
-                        width: `calc(100% - ${indent * 2}px)`,
-                        marginLeft: indent,
-                        marginRight: indent,
-                        gridTemplateColumns: 'auto auto',
-                        borderTop: 'solid',
-                    }}>
-                    <div className="slider-text">Fast</div>
-                    <div className="slider-text">Slow</div>
-                </div>{' '}
-                <div className="propertiesView-input inline">
-                    <p>Play Target Audio</p>
-                    <button
-                        style={{ background: !this.sourceAnchor?.followLinkAudio ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkAudio', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Zoom Text Selections</p>
-                    <button
-                        style={{ background: !this.sourceAnchor?.followLinkZoomText ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoomText', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Toggle Follow to Outer Context</p>
-                    <button
-                        style={{ background: !this.sourceAnchor?.followLinkToOuterContext ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToOuterContext', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faWindowMaximize as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Toggle Target (Show/Hide)</p>
-                    <button
-                        style={{ background: !this.sourceAnchor?.followLinkToggle ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToggle', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Ease Transitions</p>
-                    <button
-                        style={{ background: this.sourceAnchor?.followLinkEase === 'linear' ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkEase', this.sourceAnchor, 'ease', 'linear')}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Capture Offset to Target</p>
-                    <button
-                        style={{ background: this.sourceAnchor?.followLinkXoffset === undefined ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => {
-                            this.toggleAnchorProp(e, 'followLinkXoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.x) - NumCast(this.sourceAnchor?.x), undefined);
-                            this.toggleAnchorProp(e, 'followLinkYoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.y) - NumCast(this.sourceAnchor?.y), undefined);
-                        }}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Center Target (no zoom)</p>
-                    <button
-                        style={{ background: this.sourceAnchor?.followLinkZoom ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline" style={{ display: 'grid', gridTemplateColumns: '78px calc(100% - 108px) 50px' }}>
-                    <p>Zoom %</p>
-                    <div className="ribbon-property" style={{ display: !targZoom ? 'none' : 'inline-flex' }}>
-                        <input className="presBox-input" style={{ width: '100%' }} readOnly={true} type="number" value={zoom} />
-                        <div className="ribbon-propertyUpDown" style={{ display: 'flex', flexDirection: 'column' }}>
-                            <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), 0.1))}>
-                                <FontAwesomeIcon icon={'caret-up'} />
+                {!hasSelectedAnchor ? null : (
+                    <div className="propertiesView-section">
+                        <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 84px)' }}>
+                            <p>Follow by</p>
+                            <select onChange={e => this.changeFollowBehavior(e.currentTarget.value === 'Default' ? undefined : e.currentTarget.value)} value={Cast(this.sourceAnchor?.followLinkLocation, 'string', null)}>
+                                <option value={undefined}>Default</option>
+                                <option value={OpenWhere.addLeft}>Opening in new left pane</option>
+                                <option value={OpenWhere.addRight}>Opening in new right pane</option>
+                                <option value={OpenWhere.replaceLeft}>Replacing left tab</option>
+                                <option value={OpenWhere.replaceRight}>Replacing right tab</option>
+                                <option value={OpenWhere.lightbox}>Opening in lightbox</option>
+                                <option value={OpenWhere.add}>Opening in new tab</option>
+                                <option value={OpenWhere.replace}>Replacing current tab</option>
+                                <option value={OpenWhere.inParent}>Opening in same collection</option>
+                                {LinkManager.currentLink?.linksToAnnotation ? <option value="openExternal">Open in external page</option> : null}
+                            </select>
+                        </div>
+                        <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 134px) 50px' }}>
+                            <p>Animation</p>
+                            <select style={{ width: '100%', gridColumn: 2 }} onChange={e => this.changeAnimationBehavior(e.currentTarget.value)} value={StrCast(this.sourceAnchor?.followLinkAnimEffect, 'default')}>
+                                <option value="default">Default</option>
+                                {[PresEffect.None, PresEffect.Zoom, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => (
+                                    <option key={effect.toString()} value={effect.toString()}>
+                                        {effect.toString()}
+                                    </option>
+                                ))}
+                            </select>
+                            <div className="effectDirection" style={{ marginLeft: '10px', display: 'grid', width: 40, height: 36, gridColumn: 3, gridTemplateRows: '12px 12px 12px' }}>
+                                {this.animationDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})}
+                                {this.animationDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})}
+                                {this.animationDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})}
+                                {this.animationDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})}
+                                {this.animationDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
                             </div>
-                            <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), -0.1))}>
-                                <FontAwesomeIcon icon={'caret-down'} />
+                        </div>
+                        {PresBox.inputter(
+                            '0.1',
+                            '0.1',
+                            '10',
+                            NumCast(this.sourceAnchor?.followLinkTransitionTime) / 1000,
+                            true,
+                            (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => this.sourceAnchor && (this.sourceAnchor.followLinkTransitionTime = timeInMS)),
+                            indent
+                        )}{' '}
+                        <div
+                            className={'slider-headers'}
+                            style={{
+                                display: 'grid',
+                                justifyContent: 'space-between',
+                                width: `calc(100% - ${indent * 2}px)`,
+                                marginLeft: indent,
+                                marginRight: indent,
+                                gridTemplateColumns: 'auto auto',
+                                borderTop: 'solid',
+                            }}>
+                            <div className="slider-text">Fast</div>
+                            <div className="slider-text">Slow</div>
+                        </div>{' '}
+                        <div className="propertiesView-input inline">
+                            <p>Play Target Audio</p>
+                            <button
+                                style={{ background: !this.sourceAnchor?.followLinkAudio ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkAudio', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Zoom Text Selections</p>
+                            <button
+                                style={{ background: !this.sourceAnchor?.followLinkZoomText ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoomText', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Toggle Follow to Outer Context</p>
+                            <button
+                                style={{ background: !this.sourceAnchor?.followLinkToOuterContext ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToOuterContext', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faWindowMaximize as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Toggle Target (Show/Hide)</p>
+                            <button
+                                style={{ background: !this.sourceAnchor?.followLinkToggle ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToggle', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Ease Transitions</p>
+                            <button
+                                style={{ background: this.sourceAnchor?.followLinkEase === 'linear' ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkEase', this.sourceAnchor, 'ease', 'linear')}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Capture Offset to Target</p>
+                            <button
+                                style={{ background: this.sourceAnchor?.followLinkXoffset === undefined ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => {
+                                    this.toggleAnchorProp(e, 'followLinkXoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.x) - NumCast(this.sourceAnchor?.x), undefined);
+                                    this.toggleAnchorProp(e, 'followLinkYoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.y) - NumCast(this.sourceAnchor?.y), undefined);
+                                }}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Center Target (no zoom)</p>
+                            <button
+                                style={{ background: this.sourceAnchor?.followLinkZoom ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline" style={{ display: 'grid', gridTemplateColumns: '78px calc(100% - 108px) 50px' }}>
+                            <p>Zoom %</p>
+                            <div className="ribbon-property" style={{ display: !targZoom ? 'none' : 'inline-flex' }}>
+                                <input className="presBox-input" style={{ width: '100%' }} readOnly={true} type="number" value={zoom} />
+                                <div className="ribbon-propertyUpDown" style={{ display: 'flex', flexDirection: 'column' }}>
+                                    <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), 0.1))}>
+                                        <FontAwesomeIcon icon={'caret-up'} />
+                                    </div>
+                                    <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), -0.1))}>
+                                        <FontAwesomeIcon icon={'caret-down'} />
+                                    </div>
+                                </div>
                             </div>
+                            <button
+                                style={{ background: !targZoom || this.sourceAnchor?.followLinkZoomScale === 0 ? '' : '#4476f7', borderRadius: 3, gridColumn: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
+                            </button>
                         </div>
+                        {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom, 30)}
+                        <div
+                            className={'slider-headers'}
+                            style={{
+                                display: !targZoom ? 'none' : 'grid',
+                                justifyContent: 'space-between',
+                                width: `calc(100% - ${indent * 2}px)`,
+                                marginLeft: indent,
+                                marginRight: indent,
+                                gridTemplateColumns: 'auto auto',
+                                borderTop: 'solid',
+                            }}>
+                            <div className="slider-text">0%</div>
+                            <div className="slider-text">100%</div>
+                        </div>{' '}
                     </div>
-                    <button
-                        style={{ background: !targZoom || this.sourceAnchor?.followLinkZoomScale === 0 ? '' : '#4476f7', borderRadius: 3, gridColumn: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
-                    </button>
-                </div>
-                {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom, 30)}
-                <div
-                    className={'slider-headers'}
-                    style={{
-                        display: !targZoom ? 'none' : 'grid',
-                        justifyContent: 'space-between',
-                        width: `calc(100% - ${indent * 2}px)`,
-                        marginLeft: indent,
-                        marginRight: indent,
-                        gridTemplateColumns: 'auto auto',
-                        borderTop: 'solid',
-                    }}>
-                    <div className="slider-text">0%</div>
-                    <div className="slider-text">100%</div>
-                </div>{' '}
-            </div>
-        )}
-    </>
+                )}
+            </>
+        );
     }
 
     /**
@@ -1723,23 +1659,20 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             width: this.props.width,
                             minWidth: this.props.width,
                         }}>
-                        <div className = "propertiesView-propAndInfoGrouping">
+                        <div className="propertiesView-propAndInfoGrouping">
                             <div className="propertiesView-title" style={{ width: this.props.width }}>
                                 Properties
                             </div>
-                            <div className = "propertiesView-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/')}>
-                                 <GrCircleInformation/> </div>
-
+                            <div className="propertiesView-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/')}>
+                                <GrCircleInformation />{' '}
+                            </div>
                         </div>
 
-                        
                         <div className="propertiesView-name">{this.editableTitle}</div>
-                        <div className = "propertiesView-type"> {this.currentType} </div>
+                        <div className="propertiesView-type"> {this.currentType} </div>
                         {this.contextsSubMenu}
                         {this.linksSubMenu}
-                        {!this.selectedDoc || !LinkManager.currentLink || (!hasSelectedAnchor && this.selectedDoc !== LinkManager.currentLink) ? null : (
-                            this.linkProperties
-                        )}
+                        {!this.selectedDoc || !LinkManager.currentLink || (!hasSelectedAnchor && this.selectedDoc !== LinkManager.currentLink) ? null : this.linkProperties}
                         {this.inkSubMenu}
                         {this.optionsSubMenu}
                         {this.fieldsSubMenu}
@@ -1760,7 +1693,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             Presentation
                         </div>
                         <div className="propertiesView-name" style={{ borderBottom: 0 }}>
-                         
                             {this.editableTitle}
                             <div className="propertiesView-presSelected">
                                 <div className="propertiesView-selectedCount">{PresBox.Instance.selectedArray.size} selected</div>
@@ -1772,7 +1704,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                 <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openPresTransitions = !this.openPresTransitions))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Transitions
                                     <div className="propertiesView-presTrails-title-icon">
-                                        <FontAwesomeIcon icon={this.openPresTransitions ? 'caret-down' : 'caret-right'} size="lg"  />
+                                        <FontAwesomeIcon icon={this.openPresTransitions ? 'caret-down' : 'caret-right'} size="lg" />
                                     </div>
                                 </div>
                                 {this.openPresTransitions ? <div className="propertiesView-presTrails-content">{PresBox.Instance.transitionDropdown}</div> : null}
@@ -1786,7 +1718,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Visibilty
                                     <div className="propertiesView-presTrails-title-icon">
-                                        <FontAwesomeIcon icon={this.openPresVisibilityAndDuration ? 'caret-down' : 'caret-right'} size="lg"  />
+                                        <FontAwesomeIcon icon={this.openPresVisibilityAndDuration ? 'caret-down' : 'caret-right'} size="lg" />
                                     </div>
                                 </div>
                                 {this.openPresVisibilityAndDuration ? <div className="propertiesView-presTrails-content">{PresBox.Instance.visibiltyDurationDropdown}</div> : null}
@@ -1797,7 +1729,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                 <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openPresProgressivize = !this.openPresProgressivize))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Progressivize
                                     <div className="propertiesView-presTrails-title-icon">
-                                        <FontAwesomeIcon icon={this.openPresProgressivize ? 'caret-down' : 'caret-right'} size="lg"  />
+                                        <FontAwesomeIcon icon={this.openPresProgressivize ? 'caret-down' : 'caret-right'} size="lg" />
                                     </div>
                                 </div>
                                 {this.openPresProgressivize ? <div className="propertiesView-presTrails-content">{PresBox.Instance.progressivizeDropdown}</div> : null}
@@ -1808,7 +1740,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                 <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openSlideOptions = !this.openSlideOptions))} style={{ backgroundColor: this.openSlideOptions ? 'black' : '' }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={type === DocumentType.AUDIO ? 'file-audio' : 'file-video'} /> &nbsp; {type === DocumentType.AUDIO ? 'Audio Options' : 'Video Options'}
                                     <div className="propertiesView-presTrails-title-icon">
-                                        <FontAwesomeIcon icon={this.openSlideOptions ? 'caret-down' : 'caret-right'} size="lg"  />
+                                        <FontAwesomeIcon icon={this.openSlideOptions ? 'caret-down' : 'caret-right'} size="lg" />
                                     </div>
                                 </div>
                                 {this.openSlideOptions ? <div className="propertiesView-presTrails-content">{PresBox.Instance.mediaOptionsDropdown}</div> : null}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index bbbad3690..94748e884 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -22,7 +22,7 @@ import { DocumentViewProps } from './nodes/DocumentView';
 import { FieldViewProps } from './nodes/FieldView';
 import { KeyValueBox } from './nodes/KeyValueBox';
 import { SliderBox } from './nodes/SliderBox';
-import { BsArrowDown, BsArrowUp, BsArrowDownUp } from 'react-icons/bs'
+import { BsArrowDown, BsArrowUp, BsArrowDownUp } from 'react-icons/bs';
 import './StyleProvider.scss';
 import React = require('react');
 
@@ -161,7 +161,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 ''
             );
         case StyleProp.Color:
-            if (MainView.Instance.LastButton === doc) return Doc.UserDoc().userBackgroundColor;
+            if (MainView.Instance.LastButton === doc) return SettingsManager.Instance.userBackgroundColor;
             if (Doc.IsSystem(doc!)) return StrCast(Doc.UserDoc().userColor)
             if (doc?.type === DocumentType.FONTICON) return Doc.UserDoc().userColor;
             const docColor: Opt<string> = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color));
@@ -208,12 +208,10 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 case DocumentType.PRES:        docColor = docColor || (darkScheme() ? 'transparent' : 'transparent'); break;
                 case DocumentType.FONTICON:    docColor = boxBackground ? undefined : docColor || Colors.DARK_GRAY; break;
                 case DocumentType.RTF:         docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.LIGHT_GRAY); break;
-                case DocumentType.FILTER:      docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : 'rgba(105, 105, 105, 0.432)'); break;
                 case DocumentType.INK:         docColor = doc?.stroke_isInkMask ? 'rgba(0,0,0,0.7)' : undefined; break;
                 case DocumentType.EQUATION:    docColor = docColor || 'transparent'; break;
                 case DocumentType.LABEL:       docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.LIGHT_GRAY); break;
                 case DocumentType.BUTTON:      docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.LIGHT_GRAY); break;
-                case DocumentType.LINKANCHOR:  docColor = isAnchor ? Colors.LIGHT_BLUE : 'transparent'; break;
                 case DocumentType.LINK:        docColor = (isAnchor ? docColor : '') || 'transparent'; break;
                 case DocumentType.IMG:
                 case DocumentType.WEB:
@@ -224,7 +222,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 case DocumentType.COL:
                     if (StrCast(Doc.LayoutField(doc)).includes(SliderBox.name)) break;
                     docColor = docColor || (Doc.IsSystem(doc)
-                            ? StrCast(Doc.UserDoc().userBackgroundColor)
+                            ? SettingsManager.Instance.userBackgroundColor
                             : doc.annotationOn
                             ? '#00000010' // faint interior for collections on PDFs, images, etc
                             : doc?._isGroup
diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx
index caf04cc1b..a551e5332 100644
--- a/src/client/views/UndoStack.tsx
+++ b/src/client/views/UndoStack.tsx
@@ -7,6 +7,7 @@ import { StrCast } from '../../fields/Types';
 import { Doc } from '../../fields/Doc';
 import { Popup, Type, isDark } from 'browndash-components';
 import { Colors } from './global/globalEnums';
+import { SettingsManager } from '../util/SettingsManager';
 
 interface UndoStackProps {
     width?: number;
@@ -18,35 +19,37 @@ export class UndoStack extends React.Component<UndoStackProps> {
     @observable static HideInline: boolean;
     @observable static Expand: boolean;
     render() {
-        const background = UndoManager.batchCounter.get() ? 'yellow' : StrCast(Doc.UserDoc().userBackgroundColor)
+        const background = UndoManager.batchCounter.get() ? 'yellow' : SettingsManager.Instance.userBackgroundColor;
         return this.props.inline && UndoStack.HideInline ? null : (
             <div className="undoStack-outerContainer">
-                <Popup 
+                <Popup
                     text={'Undo/Redo Stack'}
                     color={UndoManager.batchCounter.get() ? 'yellow' : StrCast(Doc.UserDoc().userVariantColor)}
                     placement={`top-start`}
                     type={Type.TERT}
                     popup={
-                    <div className="undoStack-commandsContainer" ref={r => r?.scroll({ behavior: 'auto', top: r?.scrollHeight + 20 })} 
-                        style={{ 
-                            background: background,
-                            color: isDark(background) ? Colors.LIGHT_GRAY : Colors.DARK_GRAY
-                        }}>
-                        {UndoManager.undoStackNames.map((name, i) => (
-                            <div className="undoStack-resultContainer" key={i}>
-                                <div className="undoStack-commandString">{name.replace(/[^\.]*\./, '')}</div>
-                            </div>
-                        ))}
-                        {Array.from(UndoManager.redoStackNames)
-                            .reverse()
-                            .map((name, i) => (
+                        <div
+                            className="undoStack-commandsContainer"
+                            ref={r => r?.scroll({ behavior: 'auto', top: r?.scrollHeight + 20 })}
+                            style={{
+                                background: background,
+                                color: isDark(background) ? Colors.LIGHT_GRAY : Colors.DARK_GRAY,
+                            }}>
+                            {UndoManager.undoStackNames.map((name, i) => (
                                 <div className="undoStack-resultContainer" key={i}>
-                                    <div className="undoStack-commandString" style={{ fontWeight: 'bold', color: 'red' }}>
-                                        {name.replace(/[^\.]*\./, '')}
-                                    </div>
+                                    <div className="undoStack-commandString">{name.replace(/[^\.]*\./, '')}</div>
                                 </div>
-                        ))}
-                    </div>    
+                            ))}
+                            {Array.from(UndoManager.redoStackNames)
+                                .reverse()
+                                .map((name, i) => (
+                                    <div className="undoStack-resultContainer" key={i}>
+                                        <div className="undoStack-commandString" style={{ fontWeight: 'bold', color: 'red' }}>
+                                            {name.replace(/[^\.]*\./, '')}
+                                        </div>
+                                    </div>
+                                ))}
+                        </div>
                     }
                 />
             </div>
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 16982595d..0052c4196 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -164,7 +164,7 @@ export class CollectionDockingView extends CollectionSubView() {
     public static AddSplit(document: Doc, pullSide: OpenWhereMod, stack?: any, panelName?: string, keyValue?: boolean) {
         if (document?._type_collection === CollectionViewType.Docking && !keyValue) return DashboardView.openDashboard(document);
         if (!CollectionDockingView.Instance) return false;
-        const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document && !keyValue);
+        const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document && !tab.contentItem.config.props.keyValue && !keyValue);
         if (tab) {
             tab.header.parent.setActiveContentItem(tab.contentItem);
             return true;
@@ -466,7 +466,10 @@ export class CollectionDockingView extends CollectionSubView() {
         this._flush = this._flush ?? UndoManager.StartBatch('tab movement');
         if (tab.DashDoc && ![DocumentType.PRES].includes(tab.DashDoc?.type) && !tab.contentItem.config.props.keyValue) {
             Doc.AddDocToList(Doc.MyHeaderBar, 'data', tab.DashDoc);
-            Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
+            // if you close a tab that is not embedded somewhere else (an embedded Doc can be opened simultaneously in a tab), then add the tab to recently closed
+            if (tab.DashDoc.embedContainer === this.rootDoc) tab.DashDoc.embedContainer = undefined;
+            if (!tab.DashDoc.embedContainer) Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
+            Doc.RemoveDocFromList(Doc.GetProto(tab.DashDoc), 'proto_embeddings', tab.DashDoc);
         }
         if (CollectionDockingView.Instance) {
             const dview = CollectionDockingView.Instance.props.Document;
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 5135cfb57..f65e8698f 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -181,7 +181,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
             <div
                 className="collectionMenu-container"
                 style={{
-                    background: StrCast(Doc.UserDoc().userBackgroundColor),
+                    background: SettingsManager.Instance.userBackgroundColor,
                     // borderColor: StrCast(Doc.UserDoc().userColor)
                 }}>
                 {this.contMenuButtons}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index a5c276125..056204ad3 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -669,7 +669,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         if (menuDoc) {
             const width: number = NumCast(menuDoc._width, 30);
             const height: number = NumCast(menuDoc._height, 30);
-            console.log(menuDoc.title, width, height);
             return (
                 <div className="buttonMenu-docBtn" style={{ width: width, height: height }}>
                     <DocumentView
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 00137736d..ea3b5065f 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -150,6 +150,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                 console.log('WHAAAT');
             }
             dragData.dropAction = dropAction && !isAlreadyInTree() ? dropAction : sameTree ? 'same' : dragData.dropAction;
+            e.stopPropagation();
         }
     };
 
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 67b7b39dd..d787f5262 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -396,7 +396,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         return NumCast(Cast(PresBox.Instance.activeItem.presentationTargetDoc, Doc, null)._currentFrame);
     };
     static Activate = (tabDoc: Doc) => {
-        const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(tab => tab.DashDoc === tabDoc);
+        const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(tab => tab.DashDoc === tabDoc && !tab.contentItem.config.props.keyValue);
         tab?.header.parent.setActiveContentItem(tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost)
         return tab !== undefined;
     };
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index fb23fc7f1..6e0ccd4be 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -127,7 +127,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             : this.props.treeView.fileSysMode
             ? this.doc.isFolder
                 ? this.fieldKey
-                : 'embeddings' // for displaying
+                : 'data' // file system folders display their contents (data).  used to be they displayed their embeddings but now its a tree structure and not a flat list
             : this.props.treeView.outlineMode || this.childDocs
             ? this.fieldKey
             : Doc.noviceMode
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 090cf356c..7c53bfdbe 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -377,7 +377,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             : ((doc: Doc) => {
                   Doc.GetProto(doc).data = new List<Doc>(selected);
                   Doc.GetProto(doc).title = makeGroup ? 'grouping' : 'nested freeform';
-                  !this.props.isAnnotationOverlay && Doc.AddFileOrphan(Doc.GetProto(doc));
                   doc._freeform_panX = doc._freeform_panY = 0;
                   return doc;
               })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 79842047b..256377758 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -197,7 +197,6 @@ ScriptingGlobals.add(function toggleCharStyle(charStyle: attrname, checkResult?:
 });
 
 export function checkInksToGroup() {
-    // console.log("getting here to inks group");
     if (Doc.ActiveTool === InkTool.Write) {
         CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => {
             // TODO: nda - will probably want to go through ffView unprocessed docs and then see if any of the inksToGroup docs are in it and only use those
diff --git a/src/client/views/newlightbox/ExploreView/ExploreView.tsx b/src/client/views/newlightbox/ExploreView/ExploreView.tsx
index 44a0bcd5f..a1d6375c4 100644
--- a/src/client/views/newlightbox/ExploreView/ExploreView.tsx
+++ b/src/client/views/newlightbox/ExploreView/ExploreView.tsx
@@ -12,14 +12,11 @@ export const ExploreView = (props: IExploreView) => {
         <div className={`exploreView-container`}>
             {recs &&
                 recs.map(rec => {
-                    console.log(rec.embedding, bounds);
                     const x_bound: number = Math.max(Math.abs(bounds.max_x), Math.abs(bounds.min_x));
                     const y_bound: number = Math.max(Math.abs(bounds.max_y), Math.abs(bounds.min_y));
-                    console.log(x_bound, y_bound);
                     if (rec.embedding) {
                         const x = (rec.embedding.x / x_bound) * 50;
                         const y = (rec.embedding.y / y_bound) * 50;
-                        console.log(x, y);
                         return (
                             <div className={`exploreView-doc`} onClick={() => {}} style={{ top: `calc(50% + ${y}%)`, left: `calc(50% + ${x}%)` }}>
                                 {rec.title}
diff --git a/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx b/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx
index b9d05c531..2c2f04b9f 100644
--- a/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx
+++ b/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx
@@ -22,7 +22,6 @@ export const Recommendation = (props: IRecommendation) => {
                         doc = docView.rootDoc;
                     }
                 } else if (data) {
-                    console.log(data, type);
                     switch (type) {
                         case 'YouTube':
                             console.log('create ', type, 'document');
diff --git a/src/client/views/nodes/DataVizBox/utils/D3Utils.ts b/src/client/views/nodes/DataVizBox/utils/D3Utils.ts
index e1ff6f8eb..10bfb0c64 100644
--- a/src/client/views/nodes/DataVizBox/utils/D3Utils.ts
+++ b/src/client/views/nodes/DataVizBox/utils/D3Utils.ts
@@ -34,7 +34,6 @@ export const createLineGenerator = (xScale: d3.ScaleLinear<number, number, never
 };
 
 export const xAxisCreator = (g: d3.Selection<SVGGElement, unknown, null, undefined>, height: number, xScale: d3.ScaleLinear<number, number, never>) => {
-    console.log('x axis creator being called');
     g.attr('class', 'x-axis').attr('transform', `translate(0,${height})`).call(d3.axisBottom(xScale).tickSize(15));
 };
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 70d2f95ea..d379b2b52 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,5 +1,5 @@
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx';
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
@@ -47,7 +47,6 @@ import { DocumentLinksButton } from './DocumentLinksButton';
 import './DocumentView.scss';
 import { FieldViewProps } from './FieldView';
 import { FormattedTextBox } from './formattedText/FormattedTextBox';
-import { KeyValueBox } from './KeyValueBox';
 import { LinkAnchorBox } from './LinkAnchorBox';
 import { PresEffect, PresEffectDirection } from './trails';
 import { PinProps, PresBox } from './trails/PresBox';
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 86191de63..d69009415 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -4,7 +4,7 @@ import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import wiki from 'wikijs';
 import { Doc, DocCastAsync, Opt } from '../../../fields/Doc';
-import { Height, Width } from '../../../fields/DocSymbols';
+import { DirectLinks, Height, Width } from '../../../fields/DocSymbols';
 import { Cast, DocCast, NumCast, PromiseValue, StrCast } from '../../../fields/Types';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils';
 import { DocServer } from '../../DocServer';
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index de0b57fd7..4919ee94c 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -61,7 +61,6 @@ const script = document.createElement('script');
 script.defer = true;
 script.async = true;
 script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places,drawing`;
-console.log(script.src);
 document.head.appendChild(script);
 
 /**
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 312b3c619..bbf56bdf9 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -224,7 +224,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
             const aud_chunks: any = [];
             this._audioRec.ondataavailable = (e: any) => aud_chunks.push(e.data);
             this._audioRec.onstop = async (e: any) => {
-                const [{ result }] = await Networking.UploadFilesToServer(aud_chunks.map((file: any) => ({file})));
+                const [{ result }] = await Networking.UploadFilesToServer(aud_chunks.map((file: any) => ({ file })));
                 if (!(result instanceof Error)) {
                     this.dataDoc[this.props.fieldKey + '-audio'] = new AudioField(result.accessPaths.agnostic.client);
                 }
@@ -235,9 +235,8 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
             this._videoRec.onstart = () => (this.dataDoc[this.props.fieldKey + '-recordingStart'] = new DateField(new Date()));
             this._videoRec.ondataavailable = (e: any) => vid_chunks.push(e.data);
             this._videoRec.onstop = async (e: any) => {
-                console.log('screenshotbox: upload');
                 const file = new File(vid_chunks, `${this.rootDoc[Id]}.mkv`, { type: vid_chunks[0].type, lastModified: Date.now() });
-                const [{ result }] = await Networking.UploadFilesToServer({file});
+                const [{ result }] = await Networking.UploadFilesToServer({ file });
                 this.dataDoc[this.fieldKey + '_duration'] = (new Date().getTime() - this.recordingStart!) / 1000;
                 if (!(result instanceof Error)) {
                     // convert this screenshotBox into normal videoBox
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
index 3ad3c911d..7c8a1849e 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -610,7 +610,6 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                         ' ': {
                             dataProvider: (token: any) => this.handleToken(token),
                             component: (blob: any) => {
-                                console.log('Blob', blob);
                                 return this.renderFuncListElement(blob.entity);
                             },
                             output: (item: any, trigger: any) => {
@@ -621,7 +620,6 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                         '.': {
                             dataProvider: (token: any) => this.handleToken(token),
                             component: (blob: any) => {
-                                console.log('Blob', blob);
                                 return this.renderFuncListElement(blob.entity);
                             },
                             output: (item: any, trigger: any) => {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 895bb80f0..1dcc445e8 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -96,6 +96,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     private _scrollRef: React.RefObject<HTMLDivElement> = React.createRef();
     private _editorView: Opt<EditorView>;
     public _applyingChange: string = '';
+    private _finishingLink = false;
     private _searchIndex = 0;
     private _lastTimedMark: Mark | undefined = undefined;
     private _cachedLinks: Doc[] = [];
@@ -245,7 +246,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         if (!pinProps && this._editorView?.state.selection.empty) return this.rootDoc;
         const anchor = Docs.Create.ConfigDocument({ title: StrCast(this.rootDoc.title), annotationOn: this.rootDoc });
         this.addDocument(anchor);
+        this._finishingLink = true;
         this.makeLinkAnchor(anchor, OpenWhere.addRight, undefined, 'Anchored Selection', false, addAsAnnotation);
+        this._finishingLink = false;
         PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: true } }, this.rootDoc);
         return anchor;
     };
@@ -326,7 +329,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     textChange && (dataDoc[this.fieldKey + '_modificationDate'] = new DateField(new Date(Date.now())));
                     if ((!prevData && !protoData) || newText || (!newText && !templateData)) {
                         // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
-                        if (this.props.isContentActive() && removeSelection(newJson) !== removeSelection(prevData?.Data)) {
+                        if ((this._finishingLink || this.props.isContentActive()) && removeSelection(newJson) !== removeSelection(prevData?.Data)) {
                             const numstring = NumCast(dataDoc[this.fieldKey], null);
                             dataDoc[this.fieldKey] = numstring !== undefined ? Number(newText) : new RichTextField(newJson, newText);
                             dataDoc[this.fieldKey + '_noTemplate'] = true; // mark the data field as being split from the template if it has been edited
@@ -457,8 +460,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         if (node.firstChild === null && !node.marks.find((m: Mark) => m.type.name === schema.marks.noAutoLinkAnchor.name) && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) {
                             alink =
                                 alink ??
-                                (LinkManager.Links(this.Document).find(link => Doc.AreProtosEqual(Cast(link.link_anchor_1, Doc, null), this.rootDoc) && Doc.AreProtosEqual(Cast(link.link_anchor_2, Doc, null), target)) ||
-                                    DocUtils.MakeLink(this.props.Document, target, { link_relationship: LinkManager.AutoKeywords })!);
+                                (LinkManager.Links(this.rootDoc).find(
+                                    link =>
+                                        Doc.AreProtosEqual(Cast(link.link_anchor_1, Doc, null), this.rootDoc) && //
+                                        Doc.AreProtosEqual(Cast(link.link_anchor_2, Doc, null), target)
+                                ) ||
+                                    DocUtils.MakeLink(this.rootDoc, target, { link_relationship: LinkManager.AutoKeywords })!);
                             newAutoLinks.add(alink);
                             const allAnchors = [{ href: Doc.localServerPath(target), title: 'a link', anchorId: this.props.Document[Id] }];
                             allAnchors.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.autoLinkAnchor.name)?.attrs.allAnchors ?? []));
@@ -840,7 +847,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
 
         const appearance = cm.findByDescription('Appearance...');
         const appearanceItems = appearance && 'subitems' in appearance ? appearance.subitems : [];
-        appearanceItems.push({ description: 'Change Perspective...', noexpand: true, subitems: changeItems, icon: 'external-link-alt' });
+        appearanceItems.push({ description: 'Change Style...', noexpand: true, subitems: changeItems, icon: 'external-link-alt' });
         // this.rootDoc.isTemplateDoc && appearanceItems.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.rootDoc), icon: "eye" });
 
         !Doc.noviceMode &&
@@ -1996,12 +2003,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     }
     cycleAlternateText = () => {
         if (this.layoutDoc._layout_enableAltContentUI) {
-            const usePath = this.rootDoc[`${this.props.fieldKey}_usePath`];
+            const usePath = this.rootDoc[`_${this.props.fieldKey}_usePath`];
             this.rootDoc[`_${this.props.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined;
         }
     };
     @computed get overlayAlternateIcon() {
-        const usePath = this.rootDoc[`${this.props.fieldKey}_usePath`];
+        const usePath = this.rootDoc[`_${this.props.fieldKey}_usePath`];
         return (
             <Tooltip
                 title={
@@ -2080,7 +2087,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         ? {}
                         : {
                               transform: `scale(${scale})`,
-                              transformOrigin: 'top left',
                               width: `${100 / scale}%`,
                               height: `${100 / scale}%`,
                           }),
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index ac1e7ce5d..8bafc2cef 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -243,13 +243,13 @@ export class RichTextRules {
 
             // create a text display of a metadata field on this or another document, or create a hyperlink portal to another document
             // [[<fieldKey> : <Doc>]]
-            // [[:Doc]] => hyperlink
+            // [[:docTitle]] => hyperlink
             // [[fieldKey]] => show field
             // [[fieldKey=value]] => show field and also set its value
-            // [[fieldKey:Doc]] => show field of doc
+            // [[fieldKey:docTitle]] => show field of doc
             new InputRule(new RegExp(/\[\[([a-zA-Z_\? \-0-9]*)(=[a-zA-Z_@\? /\-0-9]*)?(:[a-zA-Z_@:\.\? \-0-9]+)?\]\]$/), (state, match, start, end) => {
                 const fieldKey = match[1];
-                const docId = match[3]?.replace(':', '');
+                const docTitle = match[3]?.replace(':', '');
                 const value = match[2]?.substring(1);
                 const linkToDoc = (target: Doc) => {
                     const rstate = this.TextBox.EditorView?.state;
@@ -266,12 +266,12 @@ export class RichTextRules {
                     }
                 };
                 if (!fieldKey) {
-                    if (docId) {
-                        const target = DocServer.QUERY_SERVER_CACHE(docId);
-                        if (target) setTimeout(() => linkToDoc(target));
-                        else DocServer.GetRefField(docId).then(docx => linkToDoc((docx instanceof Doc && docx) || Docs.Create.FreeformDocument([], { title: docId + '(auto)', _width: 500, _height: 500 }, docId)));
-
-                        return state.tr.deleteRange(end - 1, end).deleteRange(start, start + 3);
+                    if (docTitle) {
+                        const target = DocServer.FindDocByTitle(docTitle);
+                        if (target) {
+                            setTimeout(() => linkToDoc(target));
+                            return state.tr.deleteRange(end - 1, end).deleteRange(start, start + 3);
+                        }
                     }
                     return state.tr;
                 }
@@ -279,8 +279,12 @@ export class RichTextRules {
                     const num = value.match(/^[0-9.]$/);
                     this.Document[DocData][fieldKey] = value === 'true' ? true : value === 'false' ? false : num ? Number(value) : value;
                 }
-                const fieldView = state.schema.nodes.dashField.create({ fieldKey, docId, hideKey: false });
-                return state.tr.setSelection(new TextSelection(state.doc.resolve(start), state.doc.resolve(end))).replaceSelectionWith(fieldView, true);
+                const target = DocServer.FindDocByTitle(docTitle);
+                if (target) {
+                    const fieldView = state.schema.nodes.dashField.create({ fieldKey, docId: target[Id], hideKey: false });
+                    return state.tr.setSelection(new TextSelection(state.doc.resolve(start), state.doc.resolve(end))).replaceSelectionWith(fieldView, true);
+                }
+                return state.tr;
             }),
 
             // create a text display of a metadata field on this or another document, or create a hyperlink portal to another document
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index b877cc36a..e35e011e2 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -17,6 +17,7 @@ import { EditorView } from 'prosemirror-view';
 import './AnchorMenu.scss';
 import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components';
 import { StrCast } from '../../../fields/Types';
+import { DocumentType } from '../../documents/DocumentTypes';
 
 @observer
 export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -262,7 +263,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
                     colorPicker={this.highlightColor}
                     color={StrCast(Doc.UserDoc().userColor)}
                 />
-                <ColorPicker colorPickerType={'github'} selectedColor={this.highlightColor} setSelectedColor={color => this.changeHighlightColor(color)} size={Size.XSMALL} />
+                <ColorPicker selectedColor={this.highlightColor} setSelectedColor={this.changeHighlightColor} size={Size.XSMALL} />
             </Group>
         );
     }
@@ -287,7 +288,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
     canSummarize = (): boolean => {
         const docs = SelectionManager.Docs();
         if (docs.length > 0) {
-            return docs.some(doc => doc.type === 'pdf' || doc.type === 'web');
+            return docs.some(doc => doc.type === DocumentType.PDF || doc.type === DocumentType.WEB);
         }
         return false;
     };
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index e911bd283..a28561107 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -18,6 +18,7 @@ import './SearchBox.scss';
 import { fetchRecommendations } from '../newlightbox/utils';
 import { IRecommendation, Recommendation } from '../newlightbox/components';
 import { Colors } from '../global/globalEnums';
+import { SettingsManager } from '../../util/SettingsManager';
 
 const DAMPENING_FACTOR = 0.9;
 const MAX_ITERATIONS = 25;
@@ -218,7 +219,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
     }
     @action
     static staticSearchCollection(rootDoc: Opt<Doc>, query: string) {
-        const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.FILTER, DocumentType.SEARCH, DocumentType.SEARCHITEM, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
+        const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.SEARCH, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
         const blockedKeys = [
             'x',
             'y',
@@ -398,22 +399,21 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
 
         if (query) {
             this.searchCollection(query);
-            const response = await fetchRecommendations('', query, [], true)
-            const recs = response.recommendations
-            const recommendations:IRecommendation[] = []
+            const response = await fetchRecommendations('', query, [], true);
+            const recs = response.recommendations;
+            const recommendations: IRecommendation[] = [];
             for (const key in recs) {
                 const title = recs[key].title;
-                console.log(title);
-                const url = recs[key].url
-                const type = recs[key].type
-                const text = recs[key].text
-                const transcript = recs[key].transcript
-                const previewUrl = recs[key].previewUrl
-                const embedding = recs[key].embedding
-                const distance = recs[key].distance
-                const source = recs[key].source
-                const related_concepts = recs[key].related_concepts
-                const docId = recs[key].doc_id
+                const url = recs[key].url;
+                const type = recs[key].type;
+                const text = recs[key].text;
+                const transcript = recs[key].transcript;
+                const previewUrl = recs[key].previewUrl;
+                const embedding = recs[key].embedding;
+                const distance = recs[key].distance;
+                const source = recs[key].source;
+                const related_concepts = recs[key].related_concepts;
+                const docId = recs[key].doc_id;
                 recommendations.push({
                     title: title,
                     data: url,
@@ -425,11 +425,11 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                     distance: Math.round(distance * 100) / 100,
                     source: source,
                     related_concepts: related_concepts,
-                    docId: docId
-                })
+                    docId: docId,
+                });
             }
-            const setRecommendations = action(() => this._recommendations = recommendations)
-            setRecommendations()
+            const setRecommendations = action(() => (this._recommendations = recommendations));
+            setRecommendations();
         }
     };
 
@@ -461,7 +461,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
      */
     @computed
     public get selectOptions() {
-        const selectValues = ['all', 'rtf', 'image', 'pdf', 'web', 'video', 'audio', 'collection'];
+        const selectValues = ['all', DocumentType.RTF, DocumentType.IMG, DocumentType.PDF, DocumentType.WEB, DocumentType.VID, DocumentType.AUDIO, DocumentType.COL];
 
         return selectValues.map(value => (
             <option key={value} value={value}>
@@ -517,19 +517,19 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                             className={className}>
                             <div className="searchBox-result-title">{title as string}</div>
                             <div className="searchBox-result-type">{formattedType}</div>
-                            <div className="searchBox-result-keys">{result[1].join(', ')}</div>
+                            <div className="searchBox-result-keys" style={{ color: SettingsManager.Instance.userVariantColor }}>
+                                {result[1].join(', ')}
+                            </div>
                         </div>
                     </Tooltip>
                 );
             }
         });
 
-        const recommendationsJSX: JSX.Element[] = this._recommendations.map((props) => (
-            <Recommendation {...props}/>
-        ))
+        const recommendationsJSX: JSX.Element[] = this._recommendations.map(props => <Recommendation {...props} />);
 
         return (
-            <div className="searchBox-container" style={{pointerEvents: 'all', background: StrCast(Doc.UserDoc().userBackgroundColor)}}>
+            <div className="searchBox-container" style={{ pointerEvents: 'all', color: SettingsManager.Instance.userColor, background: SettingsManager.Instance.userBackgroundColor }}>
                 <div className="searchBox-bar">
                     {isLinkSearch ? null : (
                         <select name="type" id="searchBox-type" className="searchBox-type" onChange={this.onSelectChange}>
@@ -552,20 +552,24 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                         ref={this._inputRef}
                     />
                 </div>
-                {resultsJSX.length > 0 && <div className="searchBox-results-container">
-                    <div className="section-header" style={{background: StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE)}}>
-                        <div className="section-title">Results</div>
-                        <div className="section-subtitle">{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}</div>
+                {resultsJSX.length > 0 && (
+                    <div className="searchBox-results-container">
+                        <div className="section-header" style={{ background: StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE) }}>
+                            <div className="section-title">Results</div>
+                            <div className="section-subtitle">{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}</div>
+                        </div>
+                        <div className="searchBox-results-view">{resultsJSX}</div>
                     </div>
-                    <div className="searchBox-results-view">{resultsJSX}</div>
-                </div>}
-                {recommendationsJSX.length > 0 && <div className="searchBox-recommendations-container">
-                    <div className="section-header" style={{background: StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE)}}>
-                        <div className="section-title">Recommendations</div>
-                        <div className="section-subtitle">{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}</div>
+                )}
+                {recommendationsJSX.length > 0 && (
+                    <div className="searchBox-recommendations-container">
+                        <div className="section-header" style={{ background: StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE) }}>
+                            <div className="section-title">Recommendations</div>
+                            <div className="section-subtitle">{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}</div>
+                        </div>
+                        <div className="searchBox-recommendations-view">{recommendationsJSX}</div>
                     </div>
-                    <div className="searchBox-recommendations-view">{recommendationsJSX}</div>
-                </div>}
+                )}
             </div>
         );
     }
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index cb8eda9de..8caba930d 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -35,10 +35,14 @@ export class TopBar extends React.Component {
         });
     };
 
-    @computed get color() { return StrCast(Doc.UserDoc().userColor, Colors.LIGHT_GRAY); }
-    @computed get variantColor() { return StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE); }
+    @computed get color() {
+        return StrCast(Doc.UserDoc().userColor, Colors.LIGHT_GRAY);
+    }
+    @computed get variantColor() {
+        return StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE);
+    }
     @computed get backgroundColor() {
-        return PingManager.Instance.IsBeating ? StrCast(Doc.UserDoc().userBackgroundColor, Colors.DARK_GRAY) : Colors.MEDIUM_GRAY;
+        return PingManager.Instance.IsBeating ? SettingsManager.Instance.userBackgroundColor : Colors.MEDIUM_GRAY;
     }
 
     @observable happyHeart: boolean = PingManager.Instance.IsBeating;
@@ -102,7 +106,7 @@ export class TopBar extends React.Component {
                     tooltip="Open Dashboards"
                     size={Size.SMALL}
                     color={this.color}
-                    style={{fontWeight: 700, fontSize: '1rem'}}
+                    style={{ fontWeight: 700, fontSize: '1rem' }}
                     onClick={(e: React.MouseEvent) => {
                         const dashView = Doc.ActiveDashboard && DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard);
                         ContextMenu.Instance.addItem({ description: 'Open Dashboard View', event: this.navigateToHome, icon: 'edit' });
@@ -134,7 +138,7 @@ export class TopBar extends React.Component {
     @computed get topbarRight() {
         return (
             <div className="topbar-right">
-                {Doc.ActiveDashboard ? 
+                {Doc.ActiveDashboard ? (
                     <Button
                         text={GetEffectiveAcl(Doc.ActiveDashboard) === AclAdmin ? 'Share' : 'View Original'}
                         type={Type.TERT}
@@ -143,15 +147,15 @@ export class TopBar extends React.Component {
                             SharingManager.Instance.open(undefined, Doc.ActiveDashboard);
                         }}
                     />
-                : null }
-                <IconButton tooltip={"Issue Reporter ⌘I"} size={Size.SMALL} color={this.color} onClick={ReportManager.Instance.open} icon={<FaBug />} />
-                <IconButton tooltip={"Documentation ⌘D"} size={Size.SMALL} color={this.color} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')} icon={<FontAwesomeIcon icon="question-circle" />} />
-                <IconButton tooltip={"Settings ⌘⇧S"} size={Size.SMALL} color={this.color} onClick={SettingsManager.Instance.open} icon={<FontAwesomeIcon icon="cog" />} />
+                ) : null}
+                <IconButton tooltip={'Issue Reporter ⌘I'} size={Size.SMALL} color={this.color} onClick={ReportManager.Instance.open} icon={<FaBug />} />
+                <IconButton tooltip={'Documentation ⌘D'} size={Size.SMALL} color={this.color} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')} icon={<FontAwesomeIcon icon="question-circle" />} />
+                <IconButton tooltip={'Settings ⌘⇧S'} size={Size.SMALL} color={this.color} onClick={SettingsManager.Instance.open} icon={<FontAwesomeIcon icon="cog" />} />
                 <IconButton
                     size={Size.SMALL}
                     onClick={ServerStats.Instance.open}
                     type={Type.TERT}
-                    tooltip={'Server is ' + (PingManager.Instance.IsBeating ? '' : 'NOT ') + 'running'}
+                    tooltip={'Server is ' + (PingManager.Instance.IsBeating ? '' : 'NOT ') + 'running ' + SettingsManager.Version}
                     color={this.happyHeart ? Colors.LIGHT_BLUE : Colors.ERROR_RED}
                     icon={<FontAwesomeIcon icon={this.happyHeart ? 'heart' : 'heart-broken'} />}
                 />
@@ -163,12 +167,14 @@ export class TopBar extends React.Component {
     render() {
         return (
             //TODO:glr Add support for light / dark mode
-            <div style={{ 
-                pointerEvents: 'all',
-                color: this.color,
-                background: this.backgroundColor,
-                // borderColor: this.color
-            }} className="topbar-container">
+            <div
+                style={{
+                    pointerEvents: 'all',
+                    color: this.color,
+                    background: this.backgroundColor,
+                    // borderColor: this.color
+                }}
+                className="topbar-container">
                 <div className="topbar-inner-container">
                     {this.topbarLeft}
                     {this.topbarCenter}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 5a411a201..eb52cff88 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -238,22 +238,6 @@ export class Doc extends RefField {
     public static get MyFilesystem() {
         return DocCast(Doc.UserDoc().myFilesystem);
     }
-    public static get MyFileOrphans() {
-        return DocCast(Doc.UserDoc().myFileOrphans);
-    }
-    public static AddFileOrphan(doc: Doc) {
-        if (
-            doc &&
-            Doc.MyFileOrphans instanceof Doc &&
-            Doc.IsDataProto(doc) &&
-            !Doc.IsSystem(doc) &&
-            ![DocumentType.CONFIG, DocumentType.KVP, DocumentType.LINK, DocumentType.LINKANCHOR].includes(doc.type as any) &&
-            !doc.isFolder &&
-            !doc.annotationOn
-        ) {
-            Doc.AddDocToList(Doc.MyFileOrphans, undefined, doc);
-        }
-    }
     public static get MyTools() {
         return DocCast(Doc.UserDoc().myTools);
     }
@@ -388,7 +372,7 @@ export class Doc extends RefField {
             } else {
                 return Cast(layoutField, Doc, null);
             }
-            return Cast(self[renderFieldKey + '-layout[' + templateLayoutDoc[Id] + ']'], Doc, null) || templateLayoutDoc;
+            return Cast(self[renderFieldKey + '_layout[' + templateLayoutDoc[Id] + ']'], Doc, null) || templateLayoutDoc;
         }
         return undefined;
     }
@@ -701,7 +685,8 @@ export namespace Doc {
     }
 
     export function BestEmbedding(doc: Doc) {
-        const bestEmbedding = Doc.GetProto(doc) ? DocListCast(doc.proto_embeddings).find(doc => !doc.embedContainer && doc.author === Doc.CurrentUserEmail) : doc;
+        const bestEmbedding = Doc.GetProto(doc) ? [doc, ...DocListCast(doc.proto_embeddings)].find(doc => !doc.embedContainer && doc.author === Doc.CurrentUserEmail) : doc;
+        bestEmbedding && Doc.AddDocToList(Doc.GetProto(doc), 'protoEmbeddings', doc);
         return bestEmbedding ?? Doc.MakeEmbedding(doc);
     }
 
@@ -782,7 +767,6 @@ export namespace Doc {
         copy.cloneOf = doc;
         cloneMap.set(doc[Id], copy);
 
-        Doc.AddFileOrphan(copy);
         return copy;
     }
     export function repairClone(clone: Doc, cloneMap: Map<string, Doc>, visited: Set<Doc>) {
@@ -917,7 +901,7 @@ export namespace Doc {
         // If it doesn't find the expanded layout, then it makes a delegate of the template layout and
         // saves it on the data doc indexed by the template layout's id.
         //
-        const expandedLayoutFieldKey = templateField + '-layout[' + templateLayoutDoc[Id] + ']';
+        const expandedLayoutFieldKey = templateField + '_layout[' + templateLayoutDoc[Id] + ']';
         let expandedTemplateLayout = targetDoc?.[expandedLayoutFieldKey];
 
         if (templateLayoutDoc.resolvedDataDoc instanceof Promise) {
@@ -985,6 +969,59 @@ export namespace Doc {
         return overwrite;
     }
 
+    export function FindReferences(infield: Doc | List<any>, references: Set<Doc>, system: boolean | undefined) {
+        if (infield instanceof List<any>) {
+            infield.forEach(val => (val instanceof Doc || val instanceof List) && FindReferences(val, references, system));
+            return;
+        }
+        const doc = infield as Doc;
+        if (references.has(doc)) {
+            references.add(doc);
+            return;
+        }
+        const excludeLists = doc.title === 'My Recently Closed' || doc.title === 'My Header Bar' || doc.title === 'My Dashboards';
+        if (system !== undefined && ((system && !Doc.IsSystem(doc)) || (!system && Doc.IsSystem(doc)))) return;
+        references.add(doc);
+        Object.keys(doc).forEach(key => {
+            if (key === 'proto') {
+                if (doc.proto instanceof Doc) {
+                    Doc.FindReferences(doc.proto, references, system);
+                }
+            } else {
+                const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
+                const field = key === 'author' ? Doc.CurrentUserEmail : ProxyField.WithoutProxy(() => doc[key]);
+                if (field instanceof RefField) {
+                    if (field instanceof Doc) {
+                        if (key === 'myLinkDatabase') {
+                            field instanceof Doc && references.add(field);
+                            // skip docs that have been closed and are scheduled for garbage collection
+                        } else {
+                            Doc.FindReferences(field, references, system);
+                        }
+                    }
+                } else if (cfield instanceof ComputedField) {
+                } else if (field instanceof ObjectField) {
+                    if (field instanceof Doc) {
+                        Doc.FindReferences(field, references, system);
+                    } else if (field instanceof List) {
+                        !excludeLists && Doc.FindReferences(field, references, system);
+                    } else if (field instanceof ProxyField) {
+                        if (key === 'myLinkDatabase') {
+                            field instanceof Doc && references.add(field);
+                            // skip docs that have been closed and are scheduled for garbage collection
+                        } else {
+                            Doc.FindReferences(field.value, references, system);
+                        }
+                    } else if (field instanceof PrefetchProxy) {
+                        Doc.FindReferences(field.value, references, system);
+                    }
+                } else if (field instanceof Promise) {
+                    debugger; //This shouldn't happend...
+                }
+            }
+        });
+    }
+
     export function MakeCopy(doc: Doc, copyProto: boolean = false, copyProtoId?: string, retitle = false): Doc {
         const copy = new Doc(copyProtoId, true);
         updateCachedAcls(copy);
@@ -1025,7 +1062,6 @@ export namespace Doc {
         if (retitle) {
             copy.title = incrementTitleCopy(StrCast(copy.title));
         }
-        Doc.AddFileOrphan(copy);
         return copy;
     }
 
@@ -1044,7 +1080,6 @@ export namespace Doc {
             if (!Doc.IsSystem(doc)) Doc.AddDocToList(doc[DocData], 'proto_embeddings', delegate);
             title && (delegate.title = title);
             delegate[Initializing] = false;
-            Doc.AddFileOrphan(delegate);
             return delegate;
         }
         return undefined;
@@ -1177,7 +1212,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[`${StrCast(layout.isTemplateForField, 'data')}-layout[` + layout[Id] + ']'], Doc, null);
+        const overrideLayout = layout && Cast(doc[`${StrCast(layout.isTemplateForField, 'data')}_layout[` + layout[Id] + ']'], Doc, null);
         return overrideLayout || doc[DocLayout] || doc;
     }
     export function SetLayout(doc: Doc, layout: Doc | string) {
diff --git a/src/fields/FieldLoader.tsx b/src/fields/FieldLoader.tsx
index 2a7b936f7..a5a71833c 100644
--- a/src/fields/FieldLoader.tsx
+++ b/src/fields/FieldLoader.tsx
@@ -6,10 +6,9 @@ import './FieldLoader.scss';
 
 @observer
 export class FieldLoader extends React.Component {
-    @observable public static ServerLoadStatus = { requested: 0, retrieved: 0 };
-    public static active = false;
+    @observable public static ServerLoadStatus = { requested: 0, retrieved: 0, message: '' };
 
     render() {
-        return <div className="fieldLoader">{`Requested: ${FieldLoader.ServerLoadStatus.requested} ... ${FieldLoader.ServerLoadStatus.retrieved} `}</div>;
+        return <div className="fieldLoader">{`${FieldLoader.ServerLoadStatus.message} request: ${FieldLoader.ServerLoadStatus.requested} ... ${FieldLoader.ServerLoadStatus.retrieved} `}</div>;
     }
 }
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index 6764f2727..337bb812f 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -143,7 +143,6 @@ export namespace DashUploadUtils {
 
     export function uploadYoutube(videoId: string): Promise<Upload.FileResponse> {
         return new Promise<Upload.FileResponse<Upload.FileInformation>>((res, rej) => {
-            console.log('Uploading YouTube video: ' + videoId);
             const name = videoId;
             const path = name.replace(/^-/, '__') + '.mp4';
             const finalPath = serverPathToFile(Directory.videos, path);
@@ -523,7 +522,7 @@ export namespace DashUploadUtils {
             try {
                 const response = await axios.post(RESIZE_FUNCTION_URL, {
                     url: requestable,
-                    filename: resolved
+                    filename: resolved,
                 });
                 writtenFiles = response.data.writtenFiles;
             } catch (err) {
-- 
cgit v1.2.3-70-g09d2

