From 0691dc220f52643f4fd5fa9a29a5c52ef59321aa Mon Sep 17 00:00:00 2001
From: Lauren Choi <laurenchoi@gmail.com>
Date: Fri, 29 Oct 2021 10:30:48 -0400
Subject: toggle properties on selection

---
 src/client/views/PropertiesView.tsx | 88 +++++++++++++++++++++++++++++++------
 1 file changed, 75 insertions(+), 13 deletions(-)

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index ab9022a84..334a44b3b 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -57,6 +57,9 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     @computed get isPres(): boolean {
         return this.selectedDoc?.type === DocumentType.PRES;
     }
+    @computed get isLink(): boolean {
+        return this.selectedDoc?.type === DocumentType.LINK;
+    }
     @computed get dataDoc() { return this.selectedDoc?.[DataSym]; }
 
     @observable layoutFields: boolean = false;
@@ -146,8 +149,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 if (key[0] === "#") {
                     rows.push(<div style={{ display: "flex", overflowY: "visible", marginBottom: "2px" }} key={key}>
                         <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key}</span>
-                    &nbsp;
-                </div>);
+                        &nbsp;
+                    </div>);
                 } else {
                     const contentElement = <EditableView key="editableView"
                         contents={contents !== undefined ? Field.toString(contents as Field) : "null"}
@@ -214,8 +217,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
                         rows.push(<div style={{ display: "flex", overflowY: "visible", marginBottom: "-1px" }} key={key}>
                             <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key + ":"}</span>
-                        &nbsp;
-                        {contentElement}
+                            &nbsp;
+                            {contentElement}
                         </div>);
                     }
                 }
@@ -855,7 +858,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 onPointerDown={action(() => this.openOptions = !this.openOptions)}
                 style={{ backgroundColor: this.openOptions ? "black" : "" }}>
                 Options
-                        <div className="propertiesView-settings-title-icon">
+                <div className="propertiesView-settings-title-icon">
                     <FontAwesomeIcon icon={this.openOptions ? "caret-down" : "caret-right"} size="lg" color="white" />
                 </div>
             </div>
@@ -872,7 +875,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 onPointerDown={action(() => this.openSharing = !this.openSharing)}
                 style={{ backgroundColor: this.openSharing ? "black" : "" }}>
                 Sharing {"&"} Permissions
-                        <div className="propertiesView-sharing-title-icon">
+                <div className="propertiesView-sharing-title-icon">
                     <FontAwesomeIcon icon={this.openSharing ? "caret-down" : "caret-right"} size="lg" color="white" />
                 </div>
             </div>
@@ -948,7 +951,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 onPointerDown={action(() => this.openFilters = !this.openFilters)}
                 style={{ backgroundColor: this.openFilters ? "black" : "" }}>
                 Filters
-                        <div className="propertiesView-filters-title-icon">
+                <div className="propertiesView-filters-title-icon">
                     <FontAwesomeIcon icon={this.openFilters ? "caret-down" : "caret-right"} size="lg" color="white" />
                 </div>
             </div>
@@ -997,7 +1000,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         onPointerDown={action(() => this.openAppearance = !this.openAppearance)}
                         style={{ backgroundColor: this.openAppearance ? "black" : "" }}>
                         Appearance
-                            <div className="propertiesView-appearance-title-icon">
+                        <div className="propertiesView-appearance-title-icon">
                             <FontAwesomeIcon icon={this.openAppearance ? "caret-down" : "caret-right"} size="lg" color="white" />
                         </div>
                     </div>
@@ -1012,7 +1015,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     onPointerDown={action(() => this.openTransform = !this.openTransform)}
                     style={{ backgroundColor: this.openTransform ? "black" : "" }}>
                     Transform
-                        <div className="propertiesView-transform-title-icon">
+                    <div className="propertiesView-transform-title-icon">
                         <FontAwesomeIcon icon={this.openTransform ? "caret-down" : "caret-right"} size="lg" color="white" />
                     </div>
                 </div>
@@ -1029,7 +1032,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 onPointerDown={action(() => this.openFields = !this.openFields)}
                 style={{ backgroundColor: this.openFields ? "black" : "" }}>
                 Fields {"&"} Tags
-                            <div className="propertiesView-fields-title-icon">
+                <div className="propertiesView-fields-title-icon">
                     <FontAwesomeIcon icon={this.openFields ? "caret-down" : "caret-right"} size="lg" color="white" />
                 </div>
             </div>
@@ -1050,7 +1053,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 onPointerDown={action(() => this.openContexts = !this.openContexts)}
                 style={{ backgroundColor: this.openContexts ? "black" : "" }}>
                 Contexts
-                        <div className="propertiesView-contexts-title-icon">
+                <div className="propertiesView-contexts-title-icon">
                     <FontAwesomeIcon icon={this.openContexts ? "caret-down" : "caret-right"} size="lg" color="white" />
                 </div>
             </div>
@@ -1064,7 +1067,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 onPointerDown={action(() => this.openLayout = !this.openLayout)}
                 style={{ backgroundColor: this.openLayout ? "black" : "" }}>
                 Layout
-                        <div className="propertiesView-layout-title-icon">
+                <div className="propertiesView-layout-title-icon">
                     <FontAwesomeIcon icon={this.openLayout ? "caret-down" : "caret-right"} size="lg" color="white" />
                 </div>
             </div>
@@ -1072,6 +1075,14 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         </div>;
     }
 
+    toggleAnchor = () => {
+        this.selectedDoc.anchor = !this.selectedDoc.anchor
+    }
+
+    toggleArrow = () => {
+        this.selectedDoc.arrow = !this.selectedDoc.arrow
+    }
+
 
 
     /**
@@ -1095,6 +1106,57 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             </div>;
 
         } else {
+            if (this.selectedDoc && this.isLink) {
+                return <div className="propertiesView">
+                    <div className="propertiesView-title">
+                        Linking
+                    </div>
+                    <div className="properties-grid col propertiesView-textInfo">
+                        Information
+                        <div className="row" id="propertiesView-label">
+                            <p>Label</p>
+                            <input type="text" />
+                        </div>
+                        <div className="row" id="propertiesView-category">
+                            <p>Label</p>
+                            <input type="text" />
+                        </div>
+                        <div className="row" id="propertiesView-description">
+                            <p>Description</p>
+                            <input type="text" />
+                        </div>
+                    </div>
+                    <div className="propertiesView-behavior">
+                        Behavior
+                        <div id="propertiesView-follow">
+                            Follow
+                            <select name="selectList" id="selectList">
+                                <option value="default">Default</option>
+                                <option value="newLeft">Open in new left pane</option>
+                                <option value="newRight">Open in new right pane</option>
+                                <option value="replaceLeft">Replace left tab</option>
+                                <option value="replaceRight">Replace right tab</option>
+                                <option value="openFull">Open full screen</option>
+                                <option value="openTab">Open in new tab</option>
+                            </select>
+                        </div>
+                        <div id="propertiesView-anchor">
+                            Auto-move anchor
+                            <button
+                                style={{ backgroundColor: this.selectedDoc.anchor ? 'blue' : 'white', width: 50, height: 50 }}
+                                onClick={this.toggleAnchor}
+                            />
+                        </div>
+                        <div id="propertiesView-arrow">
+                            Auto-move arrow
+                            <button
+                                style={{ backgroundColor: this.selectedDoc.arrow ? 'blue' : 'white', width: 50, height: 50 }}
+                                onClick={this.toggleArrow}
+                            />
+                        </div>
+                    </div>
+                </div>;
+            }
             if (this.selectedDoc && !this.isPres) {
                 return <div className="propertiesView" style={{
                     width: this.props.width,
@@ -1148,7 +1210,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             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">
+                            <div className="propertiesView-presTrails-title-icon">
                                 <FontAwesomeIcon icon={this.openPresTransitions ? "caret-down" : "caret-right"} size="lg" color="white" />
                             </div>
                         </div>
-- 
cgit v1.2.3-70-g09d2


From 428b90b9e2e902b82f3406a5062f8be6950f4862 Mon Sep 17 00:00:00 2001
From: Lauren Choi <laurenchoi@gmail.com>
Date: Fri, 29 Oct 2021 12:05:28 -0400
Subject: style properties panel

---
 src/client/views/PropertiesView.scss               | 38 ++++++++++++++++++++
 src/client/views/PropertiesView.tsx                | 40 +++++++++++-----------
 .../CollectionFreeFormLinkView.tsx                 |  4 +--
 3 files changed, 59 insertions(+), 23 deletions(-)

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/src/client/views/PropertiesView.scss b/src/client/views/PropertiesView.scss
index 554f137cb..b75e7182c 100644
--- a/src/client/views/PropertiesView.scss
+++ b/src/client/views/PropertiesView.scss
@@ -2,6 +2,7 @@
 
 .propertiesView {
     height: 100%;
+    width: 250;
     font-family: "Roboto";
     cursor: auto;
 
@@ -836,3 +837,40 @@
 .properties-flyout {
     grid-column: 2/4;
 }
+
+.propertiesView-linking {
+    padding: 5%;
+}
+
+.propertiesView-section {
+    padding: 10px 0;
+}
+
+.propertiesView-input {
+    padding: 4px 8px;
+
+    .text {
+        width: 100%;
+    }
+
+    &.first {
+        padding-top: 6px;
+    }
+
+    &.inline {
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        justify-content: space-between;
+    }
+}
+
+.propertiesView-label {
+    font-weight: bold;
+    font-size: 12.5px;
+    padding: 4px;
+    display: flex;
+    color: white;
+    padding-left: 8px;
+    background-color: rgb(51, 51, 51);
+}
\ No newline at end of file
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 334a44b3b..b5bae6652 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1111,25 +1111,25 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     <div className="propertiesView-title">
                         Linking
                     </div>
-                    <div className="properties-grid col propertiesView-textInfo">
-                        Information
-                        <div className="row" id="propertiesView-label">
+                    <div className="propertiesView-section">
+                        <p className="propertiesView-label">Information</p>
+                        <div className="propertiesView-input first" id="propertiesView-label">
                             <p>Label</p>
-                            <input type="text" />
+                            <input className="text" type="text" />
                         </div>
-                        <div className="row" id="propertiesView-category">
-                            <p>Label</p>
-                            <input type="text" />
+                        <div className="propertiesView-input" id="propertiesView-category">
+                            <p>Category</p>
+                            <input className="text" type="text" />
                         </div>
-                        <div className="row" id="propertiesView-description">
+                        <div className="propertiesView-input" id="propertiesView-description">
                             <p>Description</p>
-                            <input type="text" />
+                            <input className="text" type="text" />
                         </div>
                     </div>
-                    <div className="propertiesView-behavior">
-                        Behavior
-                        <div id="propertiesView-follow">
-                            Follow
+                    <div className="propertiesView-section">
+                        <p className="propertiesView-label">Behavior</p>
+                        <div className="propertiesView-input inline first" id="propertiesView-follow">
+                            <p>Follow</p>
                             <select name="selectList" id="selectList">
                                 <option value="default">Default</option>
                                 <option value="newLeft">Open in new left pane</option>
@@ -1140,22 +1140,22 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                 <option value="openTab">Open in new tab</option>
                             </select>
                         </div>
-                        <div id="propertiesView-anchor">
-                            Auto-move anchor
+                        <div className="propertiesView-input inline" id="propertiesView-anchor">
+                            <p>Auto-move anchor</p>
                             <button
-                                style={{ backgroundColor: this.selectedDoc.anchor ? 'blue' : 'white', width: 50, height: 50 }}
+                                style={{ backgroundColor: this.selectedDoc.anchor ? 'blue' : 'white', width: '2rem', height: '2rem' }}
                                 onClick={this.toggleAnchor}
                             />
                         </div>
-                        <div id="propertiesView-arrow">
-                            Auto-move arrow
+                        <div className="propertiesView-input inline" id="propertiesView-arrow">
+                            <p>Auto-move arrow</p>
                             <button
-                                style={{ backgroundColor: this.selectedDoc.arrow ? 'blue' : 'white', width: 50, height: 50 }}
+                                style={{ backgroundColor: this.selectedDoc.arrow ? 'blue' : 'white', width: '2rem', height: '2rem' }}
                                 onClick={this.toggleArrow}
                             />
                         </div>
                     </div>
-                </div>;
+                </div >;
             }
             if (this.selectedDoc && !this.isPres) {
                 return <div className="propertiesView" style={{
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index d4ef76221..5391061b1 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -215,9 +215,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         return !a.width || !b.width || ((!this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<>
             <path className="collectionfreeformlinkview-linkLine" style={{ pointerEvents: "all", opacity: this._opacity, stroke: SelectionManager.SelectedSchemaDoc() === this.props.LinkDocs[0] ? "red" : stroke, strokeWidth }}
                 onClick={this.onClickLine}
-                onPointerOver={() => {
-                    console.log(this.props.LinkDocs[0].directed)
-                }} />
+                d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`} />
             {textX === undefined ? (null) : <text className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown} >
                 {Field.toString(this.props.LinkDocs[0].description as any as Field)}
             </text>}
-- 
cgit v1.2.3-70-g09d2


From 54bdf1a1549e57d6d28ae977706b601384fdc3c4 Mon Sep 17 00:00:00 2001
From: Lauren Choi <laurenchoi@gmail.com>
Date: Sat, 30 Oct 2021 15:03:59 -0400
Subject: edit link description

---
 src/client/views/PropertiesView.tsx | 62 +++++++++++++++++++++++++++++++++++--
 1 file changed, 59 insertions(+), 3 deletions(-)

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index b5bae6652..69224312a 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -31,6 +31,7 @@ import { PropertiesButtons } from "./PropertiesButtons";
 import { PropertiesDocContextSelector } from "./PropertiesDocContextSelector";
 import "./PropertiesView.scss";
 import { DefaultStyleProvider } from "./StyleProvider";
+import { LinkManager } from "../util/LinkManager";
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -1084,6 +1085,55 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
 
+    @observable
+    description = Field.toString(LinkManager.currentLink?.description as any as Field);
+    @observable
+    follow = Field.toString(LinkManager.currentLink?.follow as any as Field);
+
+    @action
+    handleDescriptionChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.description = e.target.value; }
+
+    @undoBatch
+    setDescripValue = action((value: string) => {
+        if (LinkManager.currentLink) {
+            Doc.GetProto(LinkManager.currentLink).description = value;
+            return true;
+        }
+    });
+
+    @undoBatch
+    changeFollowBehavior = action((follow: string) => {
+        if (LinkManager.currentLink) {
+            Doc.GetProto(LinkManager.currentLink).followLinkLocation = follow;
+            return true;
+        }
+    });
+
+    onSelectOut = () => {
+        this.setDescripValue(this.description);
+        document.getElementById('input')?.blur();
+    }
+
+    onDescriptionKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
+        if (e.key === "Enter") {
+            this.setDescripValue(this.description);
+            document.getElementById('input')?.blur();
+        }
+    }
+
+    @computed
+    get editDescription() {
+        return <input
+            autoComplete={"off"}
+            id="input"
+            value={this.description}
+            onKeyDown={this.onDescriptionKey}
+            onBlur={this.onSelectOut}
+            onChange={this.handleDescriptionChange}
+            className="text"
+            type="text"
+        />
+    }
 
     /**
      * Handles adding and removing members from the sharing panel
@@ -1123,7 +1173,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         </div>
                         <div className="propertiesView-input" id="propertiesView-description">
                             <p>Description</p>
-                            <input className="text" type="text" />
+                            {this.editDescription}
                         </div>
                     </div>
                     <div className="propertiesView-section">
@@ -1131,8 +1181,14 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         <div className="propertiesView-input inline first" id="propertiesView-follow">
                             <p>Follow</p>
                             <select name="selectList" id="selectList">
-                                <option value="default">Default</option>
-                                <option value="newLeft">Open in new left pane</option>
+                                <option value="default" onPointerDown={() => {
+                                    this.changeFollowBehavior("default")
+                                    console.log("default")
+                                }}>Default</option>
+                                <option value="newLeft" onPointerDown={() => {
+                                    this.changeFollowBehavior("newLeft")
+                                    console.log("newLeft")
+                                }}>Open in new left pane</option>
                                 <option value="newRight">Open in new right pane</option>
                                 <option value="replaceLeft">Replace left tab</option>
                                 <option value="replaceRight">Replace right tab</option>
-- 
cgit v1.2.3-70-g09d2


From d20c02b245148524f3d6f4fd4dc2dff7a3039b06 Mon Sep 17 00:00:00 2001
From: Lauren Choi <laurenchoi@gmail.com>
Date: Sat, 30 Oct 2021 15:30:31 -0400
Subject: change follow behavior

---
 src/client/views/PropertiesView.tsx | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 69224312a..13018b268 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1087,8 +1087,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
     @observable
     description = Field.toString(LinkManager.currentLink?.description as any as Field);
-    @observable
-    follow = Field.toString(LinkManager.currentLink?.follow as any as Field);
 
     @action
     handleDescriptionChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.description = e.target.value; }
@@ -1109,6 +1107,12 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         }
     });
 
+    getCurrentFollow = () => {
+        if (LinkManager.currentLink) {
+            return StrCast(Doc.GetProto(LinkManager.currentLink).followLinkLocation);
+        }
+    }
+
     onSelectOut = () => {
         this.setDescripValue(this.description);
         document.getElementById('input')?.blur();
@@ -1180,15 +1184,13 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         <p className="propertiesView-label">Behavior</p>
                         <div className="propertiesView-input inline first" id="propertiesView-follow">
                             <p>Follow</p>
-                            <select name="selectList" id="selectList">
-                                <option value="default" onPointerDown={() => {
-                                    this.changeFollowBehavior("default")
-                                    console.log("default")
-                                }}>Default</option>
-                                <option value="newLeft" onPointerDown={() => {
-                                    this.changeFollowBehavior("newLeft")
-                                    console.log("newLeft")
-                                }}>Open in new left pane</option>
+                            <select
+                                name="selectList"
+                                id="selectList"
+                                onChange={e => this.changeFollowBehavior(e.currentTarget.value)}
+                                value={this.getCurrentFollow()}>
+                                <option value="default">Default</option>
+                                <option value="newLeft">Open in new left pane</option>
                                 <option value="newRight">Open in new right pane</option>
                                 <option value="replaceLeft">Replace left tab</option>
                                 <option value="replaceRight">Replace right tab</option>
-- 
cgit v1.2.3-70-g09d2


From c6e0352d19f2385b484e91e1bf0076452869a1db Mon Sep 17 00:00:00 2001
From: Lauren Choi <laurenchoi@gmail.com>
Date: Sat, 30 Oct 2021 15:39:22 -0400
Subject: change dropdown values and add option for annotation links

---
 src/client/views/PropertiesView.tsx | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 13018b268..b9a6a5518 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1107,6 +1107,12 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         }
     });
 
+    getCurrLink = () => {
+        if (LinkManager.currentLink) {
+            return Doc.GetProto(LinkManager.currentLink);
+        }
+    }
+
     getCurrentFollow = () => {
         if (LinkManager.currentLink) {
             return StrCast(Doc.GetProto(LinkManager.currentLink).followLinkLocation);
@@ -1190,12 +1196,16 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                 onChange={e => this.changeFollowBehavior(e.currentTarget.value)}
                                 value={this.getCurrentFollow()}>
                                 <option value="default">Default</option>
-                                <option value="newLeft">Open in new left pane</option>
-                                <option value="newRight">Open in new right pane</option>
-                                <option value="replaceLeft">Replace left tab</option>
-                                <option value="replaceRight">Replace right tab</option>
-                                <option value="openFull">Open full screen</option>
-                                <option value="openTab">Open in new tab</option>
+                                <option value="add:left">Open in new left pane</option>
+                                <option value="add:right">Open in new right pane</option>
+                                <option value="replace:left">Replace left tab</option>
+                                <option value="replace:right">Replace right tab</option>
+                                <option value="fullScreen">Open full screen</option>
+                                <option value="add">Open in new tab</option>
+                                <option value="replace">Replace current tab</option>
+                                {this.getCurrLink()?.linksToAnnotation
+                                    ? <option value="openExternal">Open in external page</option>
+                                    : null}
                             </select>
                         </div>
                         <div className="propertiesView-input inline" id="propertiesView-anchor">
-- 
cgit v1.2.3-70-g09d2


From d8fa6bd455bcb0c4b42fa5409a8e6340927aaaff Mon Sep 17 00:00:00 2001
From: Lauren Choi <laurenchoi@gmail.com>
Date: Mon, 1 Nov 2021 00:04:13 -0400
Subject: implement auto-move anchor and fix changing follow behavior

---
 src/client/views/PropertiesView.tsx | 49 +++++++++++--------------------------
 1 file changed, 14 insertions(+), 35 deletions(-)

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index b9a6a5518..301936219 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1,5 +1,6 @@
 import React = require("react");
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faAnchor } from '@fortawesome/free-solid-svg-icons'
 import { Checkbox, Tooltip } from "@material-ui/core";
 import { intersection } from "lodash";
 import { action, autorun, computed, Lambda, observable } from "mobx";
@@ -12,7 +13,7 @@ import { List } from "../../fields/List";
 import { ComputedField } from "../../fields/ScriptField";
 import { BoolCast, Cast, NumCast, StrCast } from "../../fields/Types";
 import { denormalizeEmail, GetEffectiveAcl, SharingPermissions } from "../../fields/util";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from "../../Utils";
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents } from "../../Utils";
 import { DocumentType } from "../documents/DocumentTypes";
 import { CurrentUserUtils } from "../util/CurrentUserUtils";
 import { DocumentManager } from "../util/DocumentManager";
@@ -1076,15 +1077,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         </div>;
     }
 
-    toggleAnchor = () => {
-        this.selectedDoc.anchor = !this.selectedDoc.anchor
-    }
-
-    toggleArrow = () => {
-        this.selectedDoc.arrow = !this.selectedDoc.arrow
-    }
-
-
     @observable
     description = Field.toString(LinkManager.currentLink?.description as any as Field);
 
@@ -1102,23 +1094,11 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     @undoBatch
     changeFollowBehavior = action((follow: string) => {
         if (LinkManager.currentLink) {
-            Doc.GetProto(LinkManager.currentLink).followLinkLocation = follow;
+            this.selectedDoc.followLinkLocation = follow;
             return true;
         }
     });
 
-    getCurrLink = () => {
-        if (LinkManager.currentLink) {
-            return Doc.GetProto(LinkManager.currentLink);
-        }
-    }
-
-    getCurrentFollow = () => {
-        if (LinkManager.currentLink) {
-            return StrCast(Doc.GetProto(LinkManager.currentLink).followLinkLocation);
-        }
-    }
-
     onSelectOut = () => {
         this.setDescripValue(this.description);
         document.getElementById('input')?.blur();
@@ -1131,6 +1111,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         }
     }
 
+    toggleAnchor = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc.linkAutoMove = !this.selectedDoc.linkAutoMove)));
+    }
+
     @computed
     get editDescription() {
         return <input
@@ -1194,7 +1178,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                 name="selectList"
                                 id="selectList"
                                 onChange={e => this.changeFollowBehavior(e.currentTarget.value)}
-                                value={this.getCurrentFollow()}>
+                                value={StrCast(this.selectedDoc.followLinkLocation, "default")}>
                                 <option value="default">Default</option>
                                 <option value="add:left">Open in new left pane</option>
                                 <option value="add:right">Open in new right pane</option>
@@ -1203,7 +1187,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                 <option value="fullScreen">Open full screen</option>
                                 <option value="add">Open in new tab</option>
                                 <option value="replace">Replace current tab</option>
-                                {this.getCurrLink()?.linksToAnnotation
+                                {this.selectedDoc.linksToAnnotation
                                     ? <option value="openExternal">Open in external page</option>
                                     : null}
                             </select>
@@ -1211,16 +1195,11 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         <div className="propertiesView-input inline" id="propertiesView-anchor">
                             <p>Auto-move anchor</p>
                             <button
-                                style={{ backgroundColor: this.selectedDoc.anchor ? 'blue' : 'white', width: '2rem', height: '2rem' }}
-                                onClick={this.toggleAnchor}
-                            />
-                        </div>
-                        <div className="propertiesView-input inline" id="propertiesView-arrow">
-                            <p>Auto-move arrow</p>
-                            <button
-                                style={{ backgroundColor: this.selectedDoc.arrow ? 'blue' : 'white', width: '2rem', height: '2rem' }}
-                                onClick={this.toggleArrow}
-                            />
+                                style={{ background: this.selectedDoc.hidden ? "gray" : !this.selectedDoc.linkAutoMove ? "" : "#4476f7", borderRadius: 3 }}
+                                onPointerDown={this.toggleAnchor} onClick={e => e.stopPropagation()}
+                            >
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor} size="lg" />
+                            </button>
                         </div>
                     </div>
                 </div >;
-- 
cgit v1.2.3-70-g09d2


From 6a8eee54689f4bbe24c884895e0d2af1f06c4aad Mon Sep 17 00:00:00 2001
From: Lauren Choi <laurenchoi@gmail.com>
Date: Thu, 4 Nov 2021 14:20:58 -0400
Subject: change color of line, remove input

---
 src/client/views/PropertiesView.tsx                                 | 6 +-----
 .../collections/collectionFreeForm/CollectionFreeFormLinkView.tsx   | 3 ++-
 2 files changed, 3 insertions(+), 6 deletions(-)

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 301936219..d65db3a6b 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1157,11 +1157,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     </div>
                     <div className="propertiesView-section">
                         <p className="propertiesView-label">Information</p>
-                        <div className="propertiesView-input first" id="propertiesView-label">
-                            <p>Label</p>
-                            <input className="text" type="text" />
-                        </div>
-                        <div className="propertiesView-input" id="propertiesView-category">
+                        <div className="propertiesView-input first" id="propertiesView-category">
                             <p>Category</p>
                             <input className="text" type="text" />
                         </div>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 5391061b1..9d256f18b 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -12,6 +12,7 @@ import { DocumentView } from "../../nodes/DocumentView";
 import "./CollectionFreeFormLinkView.scss";
 import React = require("react");
 import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
+import { Colors } from "../../global/globalEnums";
 
 
 export interface CollectionFreeFormLinkViewProps {
@@ -213,7 +214,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         const strokeWidth = linkSize === -1 ? "3px" : Math.floor(2 + 10 * (linkSize / Math.max(...linkRelationshipSizes))) + "px";
 
         return !a.width || !b.width || ((!this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<>
-            <path className="collectionfreeformlinkview-linkLine" style={{ pointerEvents: "all", opacity: this._opacity, stroke: SelectionManager.SelectedSchemaDoc() === this.props.LinkDocs[0] ? "red" : stroke, strokeWidth }}
+            <path className="collectionfreeformlinkview-linkLine" style={{ pointerEvents: "all", opacity: this._opacity, stroke: SelectionManager.SelectedSchemaDoc() === this.props.LinkDocs[0] ? Colors.MEDIUM_BLUE : stroke, strokeWidth }}
                 onClick={this.onClickLine}
                 d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`} />
             {textX === undefined ? (null) : <text className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown} >
-- 
cgit v1.2.3-70-g09d2


From acbd47f286ffe05fb025151990c3128bee8e5d20 Mon Sep 17 00:00:00 2001
From: Lauren Choi <laurenchoi@gmail.com>
Date: Thu, 4 Nov 2021 16:04:27 -0400
Subject: working on link relationships

---
 src/client/views/PropertiesView.tsx | 122 ++++++++++++++++++++++++++++++++----
 1 file changed, 110 insertions(+), 12 deletions(-)

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index d65db3a6b..dd6e0e3e7 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -6,7 +6,7 @@ import { intersection } from "lodash";
 import { action, autorun, computed, Lambda, observable } from "mobx";
 import { observer } from "mobx-react";
 import { ColorState, SketchPicker } from "react-color";
-import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, AclSelfEdit, AclSym, AclUnset, DataSym, Doc, Field, HeightSym, Opt, WidthSym } from "../../fields/Doc";
+import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, AclSelfEdit, AclSym, AclUnset, DataSym, Doc, Field, HeightSym, NumListCast, Opt, StrListCast, WidthSym } from "../../fields/Doc";
 import { Id } from "../../fields/FieldSymbols";
 import { InkField } from "../../fields/InkField";
 import { List } from "../../fields/List";
@@ -1079,14 +1079,86 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
     @observable
     description = Field.toString(LinkManager.currentLink?.description as any as Field);
+    // @observable
+    // linkRelationship = Field.toString(LinkManager.currentLink?.linkRelationship as any as Field);
+    @observable relationship = StrCast(LinkManager.currentLink?.linkRelationship);
+    @observable
+    private relationshipButtonColor: string = "";
 
-    @action
-    handleDescriptionChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.description = e.target.value; }
+    // @action
+    // handleDescriptionChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.description = e.target.value; }
+    // handleRelationshipChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.relationship = e.target.value; }
+
+    @undoBatch
+    handleDescriptionChange = action((value: string) => {
+        if (LinkManager.currentLink) {
+            // this.description = value;
+            console.log("changing description to " + value)
+            this.selectedDoc.description = value;
+            return true;
+        }
+    });
+
+    @undoBatch
+    handleLinkRelationshipChange = action((value: string) => {
+        if (LinkManager.currentLink) {
+            // this.relationship = value;
+            console.log("changing linkRelationship to " + value)
+            this.selectedDoc.relationship = value;
+            return true;
+        }
+    });
 
     @undoBatch
     setDescripValue = action((value: string) => {
         if (LinkManager.currentLink) {
             Doc.GetProto(LinkManager.currentLink).description = value;
+            console.log("the link description was set to " + Doc.GetProto(LinkManager.currentLink).description)
+            // this.selectedDoc.description = value;
+            // this.description = value;
+            return true;
+        }
+    });
+
+    @undoBatch
+    setLinkRelationshipValue = action((value: string) => {
+        if (LinkManager.currentLink) {
+            const prevRelationship = LinkManager.currentLink.linkRelationship as string;
+            LinkManager.currentLink.linkRelationship = value;
+            Doc.GetProto(LinkManager.currentLink).linkRelationship = value;
+            const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList);
+            const linkRelationshipSizes = NumListCast(Doc.UserDoc().linkRelationshipSizes);
+            const linkColorList = StrListCast(Doc.UserDoc().linkColorList);
+
+            // if the relationship does not exist in the list, add it and a corresponding unique randomly generated color 
+            if (!linkRelationshipList?.includes(value)) {
+                linkRelationshipList.push(value);
+                linkRelationshipSizes.push(1);
+                const randColor = "rgb(" + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + ")";
+                linkColorList.push(randColor);
+                // if the relationship is already in the list AND the new rel is different from the prev rel, update the rel sizes
+            } else if (linkRelationshipList && value !== prevRelationship) {
+                const index = linkRelationshipList.indexOf(value);
+                //increment size of new relationship size
+                if (index !== -1 && index < linkRelationshipSizes.length) {
+                    const pvalue = linkRelationshipSizes[index];
+                    linkRelationshipSizes[index] = (pvalue === undefined || !Number.isFinite(pvalue) ? 1 : pvalue + 1);
+                }
+                //decrement the size of the previous relationship if it already exists (i.e. not default 'link' relationship upon link creation)
+                if (linkRelationshipList.includes(prevRelationship)) {
+                    const pindex = linkRelationshipList.indexOf(prevRelationship);
+                    if (pindex !== -1 && pindex < linkRelationshipSizes.length) {
+                        const pvalue = linkRelationshipSizes[pindex];
+                        linkRelationshipSizes[pindex] = Math.max(0, (pvalue === undefined || !Number.isFinite(pvalue) ? 1 : pvalue - 1));
+                    }
+                }
+
+            }
+            this.relationshipButtonColor = "rgb(62, 133, 55)";
+            console.log("the linkRelationship was set to " + Doc.GetProto(LinkManager.currentLink).linkRelationship)
+            // this.selectedDoc.relationship = value;
+            // this.relationship = value;
+            setTimeout(action(() => this.relationshipButtonColor = ""), 750);
             return true;
         }
     });
@@ -1099,15 +1171,27 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         }
     });
 
-    onSelectOut = () => {
+    onSelectOutDesc = () => {
         this.setDescripValue(this.description);
-        document.getElementById('input')?.blur();
+        document.getElementById('link_description_input')?.blur();
     }
 
     onDescriptionKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
         if (e.key === "Enter") {
             this.setDescripValue(this.description);
-            document.getElementById('input')?.blur();
+            document.getElementById('link_description_input')?.blur();
+        }
+    }
+
+    onSelectOutRelationship = () => {
+        this.setLinkRelationshipValue(this.relationship);
+        document.getElementById('link_relationship_input')?.blur();
+    }
+
+    onRelationshipKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
+        if (e.key === "Enter") {
+            this.setLinkRelationshipValue(this.relationship);
+            document.getElementById('link_relationship_input')?.blur();
         }
     }
 
@@ -1115,15 +1199,29 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc.linkAutoMove = !this.selectedDoc.linkAutoMove)));
     }
 
+    @computed
+    get editRelationship() {
+        return <input
+            autoComplete={"off"}
+            id="link_relationship_input"
+            value={StrCast(this.selectedDoc.relationship)}
+            onKeyDown={this.onRelationshipKey}
+            onBlur={this.onSelectOutRelationship}
+            onChange={e => this.handleLinkRelationshipChange(e.currentTarget.value)}
+            className="text"
+            type="text"
+        />
+    }
+
     @computed
     get editDescription() {
         return <input
             autoComplete={"off"}
-            id="input"
-            value={this.description}
+            id="link_description_input"
+            value={StrCast(this.selectedDoc.description)}
             onKeyDown={this.onDescriptionKey}
-            onBlur={this.onSelectOut}
-            onChange={this.handleDescriptionChange}
+            onBlur={this.onSelectOutDesc}
+            onChange={e => this.handleDescriptionChange(e.currentTarget.value)}
             className="text"
             type="text"
         />
@@ -1158,8 +1256,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     <div className="propertiesView-section">
                         <p className="propertiesView-label">Information</p>
                         <div className="propertiesView-input first" id="propertiesView-category">
-                            <p>Category</p>
-                            <input className="text" type="text" />
+                            <p>Link Relationship</p>
+                            {this.editRelationship}
                         </div>
                         <div className="propertiesView-input" id="propertiesView-description">
                             <p>Description</p>
-- 
cgit v1.2.3-70-g09d2


From 6d789877e2bec0812060fce9cfded2780d2e772b Mon Sep 17 00:00:00 2001
From: Lauren Choi <laurenchoi@gmail.com>
Date: Thu, 4 Nov 2021 16:36:30 -0400
Subject: link relationships working

---
 src/client/views/PropertiesView.tsx | 24 ++++++------------------
 1 file changed, 6 insertions(+), 18 deletions(-)

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index dd6e0e3e7..2d461f7ef 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1077,13 +1077,9 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         </div>;
     }
 
-    @observable
-    description = Field.toString(LinkManager.currentLink?.description as any as Field);
-    // @observable
-    // linkRelationship = Field.toString(LinkManager.currentLink?.linkRelationship as any as Field);
+    @observable description = Field.toString(LinkManager.currentLink?.description as any as Field);
     @observable relationship = StrCast(LinkManager.currentLink?.linkRelationship);
-    @observable
-    private relationshipButtonColor: string = "";
+    @observable private relationshipButtonColor: string = "";
 
     // @action
     // handleDescriptionChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.description = e.target.value; }
@@ -1092,9 +1088,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     @undoBatch
     handleDescriptionChange = action((value: string) => {
         if (LinkManager.currentLink) {
-            // this.description = value;
-            console.log("changing description to " + value)
             this.selectedDoc.description = value;
+            this.description = value;
             return true;
         }
     });
@@ -1102,9 +1097,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     @undoBatch
     handleLinkRelationshipChange = action((value: string) => {
         if (LinkManager.currentLink) {
-            // this.relationship = value;
-            console.log("changing linkRelationship to " + value)
-            this.selectedDoc.relationship = value;
+            this.selectedDoc.linkRelationship = value;
+            this.relationship = value;
             return true;
         }
     });
@@ -1113,9 +1107,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     setDescripValue = action((value: string) => {
         if (LinkManager.currentLink) {
             Doc.GetProto(LinkManager.currentLink).description = value;
-            console.log("the link description was set to " + Doc.GetProto(LinkManager.currentLink).description)
-            // this.selectedDoc.description = value;
-            // this.description = value;
             return true;
         }
     });
@@ -1155,9 +1146,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
             }
             this.relationshipButtonColor = "rgb(62, 133, 55)";
-            console.log("the linkRelationship was set to " + Doc.GetProto(LinkManager.currentLink).linkRelationship)
-            // this.selectedDoc.relationship = value;
-            // this.relationship = value;
             setTimeout(action(() => this.relationshipButtonColor = ""), 750);
             return true;
         }
@@ -1204,7 +1192,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return <input
             autoComplete={"off"}
             id="link_relationship_input"
-            value={StrCast(this.selectedDoc.relationship)}
+            value={StrCast(this.selectedDoc.linkRelationship)}
             onKeyDown={this.onRelationshipKey}
             onBlur={this.onSelectOutRelationship}
             onChange={e => this.handleLinkRelationshipChange(e.currentTarget.value)}
-- 
cgit v1.2.3-70-g09d2


From f350591b82012d94a8217d5096094de183de7bb8 Mon Sep 17 00:00:00 2001
From: Lauren Choi <laurenchoi@gmail.com>
Date: Thu, 18 Nov 2021 11:34:38 -0500
Subject: added arrow toggling functionality

---
 src/client/views/PropertiesView.scss                    |  4 ++++
 src/client/views/PropertiesView.tsx                     | 17 ++++++++++++++++-
 .../collectionFreeForm/CollectionFreeFormLinkView.tsx   |  8 +++++++-
 src/fields/documentSchemas.ts                           |  1 +
 4 files changed, 28 insertions(+), 2 deletions(-)

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/src/client/views/PropertiesView.scss b/src/client/views/PropertiesView.scss
index b75e7182c..437df4739 100644
--- a/src/client/views/PropertiesView.scss
+++ b/src/client/views/PropertiesView.scss
@@ -863,6 +863,10 @@
         align-items: center;
         justify-content: space-between;
     }
+
+    .propertiesButton {
+        width: 4rem;
+    }
 }
 
 .propertiesView-label {
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 2d461f7ef..936003dce 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1,6 +1,6 @@
 import React = require("react");
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faAnchor } from '@fortawesome/free-solid-svg-icons'
+import { faAnchor, faArrowRight } from '@fortawesome/free-solid-svg-icons'
 import { Checkbox, Tooltip } from "@material-ui/core";
 import { intersection } from "lodash";
 import { action, autorun, computed, Lambda, observable } from "mobx";
@@ -1187,6 +1187,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc.linkAutoMove = !this.selectedDoc.linkAutoMove)));
     }
 
+    toggleArrow = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc.displayArrow = !this.selectedDoc.displayArrow)));
+    }
+
     @computed
     get editRelationship() {
         return <input
@@ -1279,10 +1283,21 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             <button
                                 style={{ background: this.selectedDoc.hidden ? "gray" : !this.selectedDoc.linkAutoMove ? "" : "#4476f7", borderRadius: 3 }}
                                 onPointerDown={this.toggleAnchor} onClick={e => e.stopPropagation()}
+                                className="propertiesButton"
                             >
                                 <FontAwesomeIcon className="fa-icon" icon={faAnchor} size="lg" />
                             </button>
                         </div>
+                        <div className="propertiesView-input inline" id="propertiesView-displayArrow">
+                            <p>Display arrow</p>
+                            <button
+                                style={{ background: this.selectedDoc.hidden ? "gray" : !this.selectedDoc.displayArrow ? "" : "#4476f7", borderRadius: 3 }}
+                                onPointerDown={this.toggleArrow} onClick={e => e.stopPropagation()}
+                                className="propertiesButton"
+                            >
+                                <FontAwesomeIcon className="fa-icon" icon={faArrowRight} size="lg" />
+                            </button>
+                        </div>
                     </div>
                 </div >;
             }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 43f181849..da4edbaa2 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -233,6 +233,12 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         //thickness varies linearly from 3px to 12px for increasing link count
         const strokeWidth = linkSize === -1 ? "3px" : Math.floor(2 + 10 * (linkSize / Math.max(...linkRelationshipSizes))) + "px";
 
+        console.log(this.props.LinkDocs[0].displayArrow)
+
+        if (this.props.LinkDocs[0].displayArrow == undefined) {
+            this.props.LinkDocs[0].displayArrow = false;
+        }
+
         return !a.width || !b.width || ((!this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<>
             <defs>
                 <marker id="arrowhead" markerWidth="4" markerHeight="3"
@@ -243,7 +249,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
             <path className="collectionfreeformlinkview-linkLine" style={{ pointerEvents: "all", opacity: this._opacity, stroke: SelectionManager.SelectedSchemaDoc() === this.props.LinkDocs[0] ? Colors.MEDIUM_BLUE : stroke, strokeWidth }}
                 onClick={this.onClickLine}
                 d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`}
-                markerEnd="url(#arrowhead)" />
+                markerEnd={this.props.LinkDocs[0].displayArrow ? "url(#arrowhead)" : ""} />
             {textX === undefined ? (null) : <text className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown} >
                 {Field.toString(this.props.LinkDocs[0].description as any as Field)}
             </text>}
diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts
index db2c6ca5b..73157d268 100644
--- a/src/fields/documentSchemas.ts
+++ b/src/fields/documentSchemas.ts
@@ -93,6 +93,7 @@ export const documentSchema = createSchema({
     layers: listSpec("string"), // which layers the document is part of
     _lockedPosition: "boolean",  // whether the document can be moved (dragged)
     _lockedTransform: "boolean",// whether a freeformview can pan/zoom
+    displayArrow: "boolean", // toggles directed arrows
 
     // drag drop properties
     _stayInCollection: "boolean",// whether document can be dropped into a different collection
-- 
cgit v1.2.3-70-g09d2

