aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFawn <fangrui_tong@brown.edu>2019-06-14 15:24:35 -0400
committerFawn <fangrui_tong@brown.edu>2019-06-14 15:24:35 -0400
commitf54496c7aa930e385e77aaf37df8d51db733e3a2 (patch)
tree6c96d5fe127bf65888511d2529fa2e7f8dc1e385 /src
parent8bcd3567df7c49523638f0b935ecd09b1acad45d (diff)
cleaned up link code
Diffstat (limited to 'src')
-rw-r--r--src/client/util/LinkManager.ts166
-rw-r--r--src/client/views/nodes/LinkBox.scss122
-rw-r--r--src/client/views/nodes/LinkBox.tsx52
-rw-r--r--src/client/views/nodes/LinkEditor.scss106
-rw-r--r--src/client/views/nodes/LinkEditor.tsx319
-rw-r--r--src/client/views/nodes/LinkMenu.scss76
-rw-r--r--src/client/views/nodes/LinkMenu.tsx54
7 files changed, 311 insertions, 584 deletions
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 929fcbf21..aaed7388d 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -1,71 +1,9 @@
-import { observable, computed, action } from "mobx";
-import React = require("react");
-import { SelectionManager } from "./SelectionManager";
-import { observer } from "mobx-react";
-import { props } from "bluebird";
-import { DocumentView } from "../views/nodes/DocumentView";
-import { link } from "fs";
+import { observable } from "mobx";
import { StrCast, Cast } from "../../new_fields/Types";
-import { Doc } from "../../new_fields/Doc";
+import { Doc, DocListCast } from "../../new_fields/Doc";
import { listSpec } from "../../new_fields/Schema";
import { List } from "../../new_fields/List";
-import { string } from "prop-types";
-import { Docs } from "../documents/Documents";
-export namespace LinkUtils {
- export function findOppositeAnchor(link: Doc, anchor: Doc): Doc {
- if (Doc.AreProtosEqual(anchor, Cast(link.anchor1, Doc, new Doc))) {
- return Cast(link.anchor2, Doc, new Doc);
- } else {
- return Cast(link.anchor1, Doc, new Doc);
- }
- }
-
- export function setAnchorGroups(link: Doc, anchor: Doc, groups: Doc[]) {
- // console.log("setting groups for anchor", anchor["title"]);
- if (Doc.AreProtosEqual(anchor, Cast(link.anchor1, Doc, new Doc))) {
- link.anchor1Groups = new List<Doc>(groups);
-
- let print: string[] = [];
- Cast(link.anchor1Groups, listSpec(Doc), []).forEach(doc => {
- if (doc instanceof Doc) {
- print.push(StrCast(doc.type));
- }
- });
- console.log("set anchor's groups as", print);
- } else {
- link.anchor2Groups = new List<Doc>(groups);
-
- let print: string[] = [];
- Cast(link.anchor2Groups, listSpec(Doc), []).forEach(doc => {
- if (doc instanceof Doc) {
- print.push(StrCast(doc.type));
- }
- });
- console.log("set anchor's groups as", print);
- }
- }
-
- export function removeGroupFromAnchor(link: Doc, anchor: Doc, groupType: string) {
- let groups = Doc.AreProtosEqual(anchor, Cast(link.anchor1, Doc, new Doc)) ?
- Cast(link.proto!.anchor1Groups, listSpec(Doc), []) : Cast(link.proto!.anchor2Groups, listSpec(Doc), []);
-
- let newGroups: Doc[] = [];
- groups.forEach(groupDoc => {
- if (groupDoc instanceof Doc && StrCast(groupDoc.type) !== groupType) {
- newGroups.push(groupDoc);
- } // TODO: promise
- });
-
- // let grouptypes: string[] = [];
- // newGroups.forEach(groupDoc => {
- // grouptypes.push(StrCast(groupDoc.type));
- // });
- // console.log("remove anchor's groups as", grouptypes);
-
- LinkUtils.setAnchorGroups(link, anchor, newGroups);
- }
-}
/*
* link doc:
@@ -94,6 +32,7 @@ export class LinkManager {
@observable public allLinks: Array<Doc> = []; // list of link docs
@observable public groupMetadataKeys: Map<string, Array<string>> = new Map(); // map of group type to list of its metadata keys
+ // finds all links that contain the given anchor
public findAllRelatedLinks(anchor: Doc): Array<Doc> {
return LinkManager.Instance.allLinks.filter(
link => Doc.AreProtosEqual(anchor, Cast(link.anchor1, Doc, new Doc)) || Doc.AreProtosEqual(anchor, Cast(link.anchor2, Doc, new Doc)));
@@ -102,27 +41,19 @@ export class LinkManager {
// returns map of group type to anchor's links in that group type
public findRelatedGroupedLinks(anchor: Doc): Map<string, Array<Doc>> {
let related = this.findAllRelatedLinks(anchor);
-
let anchorGroups = new Map<string, Array<Doc>>();
related.forEach(link => {
+ let groups = LinkManager.Instance.getAnchorGroups(link, anchor);
- // get groups of given anchor categorizes this link/opposite anchor in
- let groups = (Doc.AreProtosEqual(anchor, Cast(link.anchor1, Doc, new Doc))) ? Cast(link.anchor1Groups, listSpec(Doc), []) : Cast(link.anchor2Groups, listSpec(Doc), []);
if (groups.length > 0) {
groups.forEach(groupDoc => {
- if (groupDoc instanceof Doc) {
- let groupType = StrCast(groupDoc.type);
- let group = anchorGroups.get(groupType); // TODO: clean this up lol
- if (group) group.push(link);
- else group = [link];
- anchorGroups.set(groupType, group);
- } else {
- // promise doc
- }
-
+ let groupType = StrCast(groupDoc.type);
+ let group = anchorGroups.get(groupType);
+ if (group) group.push(link);
+ else group = [link];
+ anchorGroups.set(groupType, group);
});
- }
- else {
+ } else {
// if link is in no groups then put it in default group
let group = anchorGroups.get("*");
if (group) group.push(link);
@@ -134,52 +65,38 @@ export class LinkManager {
return anchorGroups;
}
- public findMetadataInGroup(groupType: string) {
+ // returns a list of all metadata docs associated with the given group type
+ public findAllMetadataDocsInGroup(groupType: string): Array<Doc> {
let md: Doc[] = [];
let allLinks = LinkManager.Instance.allLinks;
- // for every link find its groups
- // allLinks.forEach(linkDoc => {
- // let anchor1groups = LinkManager.Instance.findRelatedGroupedLinks(Cast(linkDoc["anchor1"], Doc, new Doc));
- // if (anchor1groups.get(groupType)) {
- // md.push(linkDoc["anchor1"]["group"])
- // }
- // })
allLinks.forEach(linkDoc => {
- let anchor1Groups = Cast(linkDoc.anchor1Groups, listSpec(Doc), []);
- let anchor2Groups = Cast(linkDoc.anchor2Groups, listSpec(Doc), []);
- anchor1Groups.forEach(groupDoc => {
- if (groupDoc instanceof Doc) {
- if (StrCast(groupDoc.type) === groupType) {
- md.push(Cast(groupDoc.metadata, Doc, new Doc));
- }
- } else {
- // TODO: promise
- }
- });
- anchor2Groups.forEach(groupDoc => {
- if (groupDoc instanceof Doc) {
- if (StrCast(groupDoc.type) === groupType) {
- md.push(Cast(groupDoc.metadata, Doc, new Doc));
- }
- } else {
- // TODO: promise
- }
- });
-
+ let anchor1Groups = LinkManager.Instance.getAnchorGroups(linkDoc, Cast(linkDoc.anchor1, Doc, new Doc));
+ let anchor2Groups = LinkManager.Instance.getAnchorGroups(linkDoc, Cast(linkDoc.anchor2, Doc, new Doc));
+ anchor1Groups.forEach(groupDoc => { if (StrCast(groupDoc.type).toUpperCase() === groupType.toUpperCase()) md.push(Cast(groupDoc.metadata, Doc, new Doc)); });
+ anchor2Groups.forEach(groupDoc => { if (StrCast(groupDoc.type).toUpperCase() === groupType.toUpperCase()) md.push(Cast(groupDoc.metadata, Doc, new Doc)); });
});
return md;
}
- public deleteGroup(groupType: string) {
+ // removes all group docs from all links with the given group type
+ public deleteGroup(groupType: string): void {
let deleted = LinkManager.Instance.groupMetadataKeys.delete(groupType);
if (deleted) {
LinkManager.Instance.allLinks.forEach(linkDoc => {
- LinkUtils.removeGroupFromAnchor(linkDoc, Cast(linkDoc.anchor1, Doc, new Doc), groupType);
- LinkUtils.removeGroupFromAnchor(linkDoc, Cast(linkDoc.anchor2, Doc, new Doc), groupType);
+ LinkManager.Instance.removeGroupFromAnchor(linkDoc, Cast(linkDoc.anchor1, Doc, new Doc), groupType);
+ LinkManager.Instance.removeGroupFromAnchor(linkDoc, Cast(linkDoc.anchor2, Doc, new Doc), groupType);
});
}
}
+ // removes group doc of given group type only from given anchor on given link
+ public removeGroupFromAnchor(linkDoc: Doc, anchor: Doc, groupType: string) {
+ let groups = LinkManager.Instance.getAnchorGroups(linkDoc, anchor);
+ let newGroups = groups.filter(groupDoc => StrCast(groupDoc.type).toUpperCase() !== groupType.toUpperCase());
+ LinkManager.Instance.setAnchorGroups(linkDoc, anchor, newGroups);
+ }
+
+ // checks if a link with the given anchors exists
public doesLinkExist(anchor1: Doc, anchor2: Doc) {
let allLinks = LinkManager.Instance.allLinks;
let index = allLinks.findIndex(linkDoc => {
@@ -189,4 +106,31 @@ export class LinkManager {
return index !== -1;
}
+ // finds the opposite anchor of a given anchor in a link
+ public findOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc {
+ if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, new Doc))) {
+ return Cast(linkDoc.anchor2, Doc, new Doc);
+ } else {
+ return Cast(linkDoc.anchor1, Doc, new Doc);
+ }
+ }
+
+ // gets the groups associates with an anchor in a link
+ public getAnchorGroups(linkDoc: Doc, anchor: Doc): Array<Doc> {
+ if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, new Doc))) {
+ return DocListCast(linkDoc.anchor1Groups);
+ } else {
+ return DocListCast(linkDoc.anchor2Groups);
+ }
+ }
+
+ // sets the groups of the given anchor in the given link
+ public setAnchorGroups(linkDoc: Doc, anchor: Doc, groups: Doc[]) {
+ if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, new Doc))) {
+ linkDoc.anchor1Groups = new List<Doc>(groups);
+ } else {
+ linkDoc.anchor2Groups = new List<Doc>(groups);
+ }
+ }
+
} \ No newline at end of file
diff --git a/src/client/views/nodes/LinkBox.scss b/src/client/views/nodes/LinkBox.scss
index 639f83b38..08fefaf4d 100644
--- a/src/client/views/nodes/LinkBox.scss
+++ b/src/client/views/nodes/LinkBox.scss
@@ -1,66 +1,62 @@
@import "../globalCssVariables";
-.link-container {
- width: 100%;
- height: 50px;
+.link-menu-item {
+ border-top: 0.5px solid $light-color-secondary;
+ padding: 6px;
+ position: relative;
display: flex;
- flex-direction: row;
- border-top: 0.5px solid #bababa;
-}
-
-.info-container {
- width: 65%;
- padding-top: 5px;
- padding-left: 5px;
- display: flex;
- flex-direction: column
-}
-
-.link-name {
- font-size: 11px;
-}
-
-.doc-name {
- font-size: 8px;
-}
-
-.button-container {
- width: 35%;
- padding-top: 8px;
- display: flex;
- flex-direction: row;
-}
-
-.button {
- height: 20px;
- width: 20px;
- margin: 8px 4px;
- border-radius: 50%;
- opacity: 0.9;
- pointer-events: auto;
- background-color: $dark-color;
- color: $light-color;
- text-transform: uppercase;
- letter-spacing: 2px;
- font-size: 60%;
- transition: transform 0.2s;
-}
-
-.button:hover {
- background: $main-accent;
- cursor: pointer;
-}
-
-// .fa-icon-view {
-// margin-left: 3px;
-// margin-top: 5px;
-// }
-
-.fa-icon-edit {
- margin-left: 6px;
- margin-top: 6px;
-}
-
-.fa-icon-delete {
- margin-left: 7px;
- margin-top: 6px;
+ font-size: 12px;
+
+ .link-menu-item-content {
+ width: 100%;
+ }
+
+ &:last-child {
+ border-bottom: 0.5px solid $light-color-secondary;
+ }
+ &:hover {
+ .link-menu-item-buttons {
+ display: flex;
+ }
+ .link-menu-item-content {
+ width: calc(100% - 42px);
+ }
+ }
+}
+
+.link-menu-item-buttons {
+ display: none;
+ position: absolute;
+ top: 50%;
+ right: 0;
+ transform: translateY(-50%);
+
+ .button {
+ width: 20px;
+ height: 20px;
+ margin: 0;
+ margin-right: 6px;
+ border-radius: 50%;
+ cursor: pointer;
+ pointer-events: auto;
+ background-color: $dark-color;
+ color: $light-color;
+ font-size: 65%;
+ transition: transform 0.2s;
+ text-align: center;
+ position: relative;
+
+ .fa-icon {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ }
+
+ &:last-child {
+ margin-right: 0;
+ }
+ &:hover {
+ background: $main-accent;
+ }
+ }
} \ No newline at end of file
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 5597bb1aa..1a7cce4a3 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -4,13 +4,10 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { observer } from "mobx-react";
import { DocumentManager } from "../../util/DocumentManager";
import { undoBatch } from "../../util/UndoManager";
-import { CollectionDockingView } from "../collections/CollectionDockingView";
import './LinkBox.scss';
import React = require("react");
import { Doc } from '../../../new_fields/Doc';
-import { Cast, NumCast } from '../../../new_fields/Types';
-import { listSpec } from '../../../new_fields/Schema';
-import { action } from 'mobx';
+import { StrCast } from '../../../new_fields/Types';
library.add(faEye);
@@ -20,9 +17,8 @@ library.add(faArrowRight);
interface Props {
linkDoc: Doc;
- linkName: String;
- pairedDoc: Doc;
- type: String;
+ sourceDoc: Doc;
+ destinationDoc: Doc;
showEditor: () => void;
}
@@ -30,58 +26,28 @@ interface Props {
export class LinkBox extends React.Component<Props> {
@undoBatch
- followLink = async (e: React.PointerEvent): Promise<void> => {
+ onFollowLink = async (e: React.PointerEvent): Promise<void> => {
e.stopPropagation();
- DocumentManager.Instance.jumpToDocument(this.props.pairedDoc, e.altKey);
+ DocumentManager.Instance.jumpToDocument(this.props.destinationDoc, e.altKey);
}
- onEditButtonPressed = (e: React.PointerEvent): void => {
+ onEdit = (e: React.PointerEvent): void => {
e.stopPropagation();
-
this.props.showEditor();
}
- // @action
- // onDeleteButtonPressed = async (e: React.PointerEvent): Promise<void> => {
- // e.stopPropagation();
- // const [linkedFrom, linkedTo] = await Promise.all([Cast(this.props.linkDoc.linkedFrom, Doc), Cast(this.props.linkDoc.linkedTo, Doc)]);
- // if (linkedFrom) {
- // const linkedToDocs = Cast(linkedFrom.linkedToDocs, listSpec(Doc));
- // if (linkedToDocs) {
- // linkedToDocs.splice(linkedToDocs.indexOf(this.props.linkDoc), 1);
- // }
- // }
- // if (linkedTo) {
- // const linkedFromDocs = Cast(linkedTo.linkedFromDocs, listSpec(Doc));
- // if (linkedFromDocs) {
- // linkedFromDocs.splice(linkedFromDocs.indexOf(this.props.linkDoc), 1);
- // }
- // }
- // }
-
render() {
-
return (
- //<LinkEditor linkBox={this} linkDoc={this.props.linkDoc} />
<div className="link-menu-item">
<div className="link-menu-item-content">
<div className="link-name">
- <p>{this.props.linkName}</p>
- </div>
- <div className="doc-name">
- <p>{this.props.type}{this.props.pairedDoc.Title}</p>
+ <p>{StrCast(this.props.destinationDoc.title)}</p>
</div>
</div>
<div className="link-menu-item-buttons">
- {/* <div title="Follow Link" className="button" onPointerDown={this.onViewButtonPressed}>
- <FontAwesomeIcon className="fa-icon-view" icon="eye" size="sm" /></div> */}
- <div title="Follow Link" className="button" onPointerDown={this.followLink}>
- <FontAwesomeIcon className="fa-icon" icon="arrow-right" size="sm" /></div>
- <div title="Edit Link" className="button" onPointerDown={this.onEditButtonPressed}>
- <FontAwesomeIcon className="fa-icon" icon="edit" size="sm" /></div>
- {/* <div title="Delete Link" className="button" onPointerDown={this.onDeleteButtonPressed}>
- <FontAwesomeIcon className="fa-icon" icon="times" size="sm" /></div> */}
+ <div title="Edit link" className="button" onPointerDown={this.onEdit}><FontAwesomeIcon className="fa-icon" icon="edit" size="sm" /></div>
+ <div title="Follow link" className="button" onPointerDown={this.onFollowLink}><FontAwesomeIcon className="fa-icon" icon="arrow-right" size="sm" /></div>
</div>
</div>
);
diff --git a/src/client/views/nodes/LinkEditor.scss b/src/client/views/nodes/LinkEditor.scss
index 01f0cb82a..6aac39f45 100644
--- a/src/client/views/nodes/LinkEditor.scss
+++ b/src/client/views/nodes/LinkEditor.scss
@@ -1,92 +1,63 @@
@import "../globalCssVariables";
-.edit-container {
+
+.linkEditor {
width: 100%;
height: auto;
- display: flex;
- flex-direction: column;
+ font-size: 12px; // TODO
}
-.name-input {
- margin-bottom: 10px;
- padding: 5px;
- font-size: 12px;
- border: 1px solid #bababa;
+.linkEditor-back {
+ margin-bottom: 6px;
}
-.description-input {
- font-size: 11px;
- padding: 5px;
- margin-bottom: 10px;
- border: 1px solid #bababa;
-}
+.linkEditor-groupsLabel {
+ display: flex;
+ justify-content: space-between;
-.save-button {
- width: 50px;
- height: 22px;
- pointer-events: auto;
- background-color: $dark-color;
- color: $light-color;
- text-transform: uppercase;
- letter-spacing: 2px;
- padding: 2px;
- font-size: 10px;
- margin: 0 auto;
- transition: transform 0.2s;
- text-align: center;
- line-height: 20px;
+ button {
+ width: 20px;
+ height: 20px;
+ margin-left: 6px;
+ padding: 0;
+ font-size: 14px;
+ }
}
-.save-button:hover {
- background: $main-accent;
- cursor: pointer;
+.linkEditor-linkedTo {
+ border-bottom: 0.5px solid $light-color-secondary;
+ padding-bottom: 6px;
+ margin-bottom: 6px;
}
-.linkEditor {
- font-size: 12px; // TODO
-
- .linkEditor-back {
- // background-color: $dark-color;
- // color: $light-color;
- margin-bottom: 6px;
- }
+.linkEditor-group {
+ background-color: $light-color-secondary;
+ padding: 6px;
+ margin: 3px 0;
+ border-radius: 3px;
- .linkEditor-groupsLabel {
- display: flex;
- justify-content: space-between;
- button {
- width: 20px;
- height: 20px;
- margin-left: 6px;
- padding: 0;
- font-size: 14px;
- }
- }
- .linkEditor-linkedTo {
- border-bottom: 0.5px solid $light-color-secondary;
- padding-bottom: 6px;
- margin-bottom: 6px;
- }
- .linkEditor-group {
- background-color: $light-color-secondary;
- padding: 6px;
- margin: 3px 0;
- border-radius: 3px;
- }
.linkEditor-group-row {
display: flex;
margin-bottom: 6px;
+
.linkEditor-group-row-label {
margin-right: 6px;
}
}
+
.linkEditor-metadata-row {
display: flex;
justify-content: space-between;
margin-bottom: 6px;
+
+ .linkEditor-error {
+ border-color: red;
+ }
+
input {
width: calc(50% - 18px);
height: 20px;
}
+
button {
width: 20px;
height: 20px;
@@ -97,10 +68,12 @@
}
}
+
.linkEditor-dropdown {
width: 100%;
position: relative;
z-index: 999;
+
.linkEditor-options-wrapper {
width: 100%;
position: absolute;
@@ -109,12 +82,14 @@
display: flex;
flex-direction: column;
}
+
.linkEditor-option {
background-color: $light-color-secondary;
border: 1px solid $intermediate-color;
border-top: 0;
padding: 3px;
cursor: pointer;
+
&:hover {
background-color: $intermediate-color;
font-weight: bold;
@@ -126,19 +101,18 @@
height: 20px;
display: flex;
justify-content: space-between;
+
.linkEditor-groupOpts {
width: calc(20% - 3px);
height: 20px;
- // margin-left: 6px;
padding: 0;
font-size: 10px;
- &:first-child { // delete
- font-size: 14px;
- }
- &:disabled { // delete
+
+ &:disabled {
background-color: gray;
}
}
+
.linkEditor-groupOpts button {
width: 100%;
height: 20px;
diff --git a/src/client/views/nodes/LinkEditor.tsx b/src/client/views/nodes/LinkEditor.tsx
index 5097d625e..484682c22 100644
--- a/src/client/views/nodes/LinkEditor.tsx
+++ b/src/client/views/nodes/LinkEditor.tsx
@@ -4,61 +4,52 @@ import { observer } from "mobx-react";
import './LinkEditor.scss';
import { StrCast, Cast } from "../../../new_fields/Types";
import { Doc } from "../../../new_fields/Doc";
-import { List } from "../../../new_fields/List";
-import { listSpec } from "../../../new_fields/Schema";
-import { LinkManager, LinkUtils } from "../../util/LinkManager";
+import { LinkManager } from "../../util/LinkManager";
import { Docs } from "../../documents/Documents";
import { Utils } from "../../../Utils";
import { faArrowLeft, faEllipsisV, faTable } from '@fortawesome/free-solid-svg-icons';
import { library } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { string } from "prop-types";
import { SetupDrag } from "../../util/DragManager";
library.add(faArrowLeft);
library.add(faEllipsisV);
library.add(faTable);
+
+interface GroupTypesDropdownProps {
+ groupId: string;
+ groupType: string;
+ setGroup: (groupId: string, group: string) => void;
+}
// this dropdown could be generalized
@observer
-class LinkGroupsDropdown extends React.Component<{ groupId: string, groupType: string, setGroup: (groupId: string, group: string) => void }> {
+class GroupTypesDropdown extends React.Component<GroupTypesDropdownProps> {
@observable private _searchTerm: string = "";
@observable private _groupType: string = this.props.groupType;
- @action
- setSearchTerm(value: string) {
- this._searchTerm = value;
- }
+ @action setSearchTerm = (value: string): void => { this._searchTerm = value; };
+ @action setGroupType = (value: string): void => { this._groupType = value; };
@action
- setGroupType(value: string) {
- this._groupType = value;
+ createGroup = (groupType: string): void => {
+ this.props.setGroup(this.props.groupId, groupType);
+ LinkManager.Instance.groupMetadataKeys.set(groupType, []);
}
- @action
- createGroup(value: string) {
- LinkManager.Instance.groupMetadataKeys.set(value, []);
- this.props.setGroup(this.props.groupId, value);
- }
+ renderOptions = (): JSX.Element[] | JSX.Element => {
+ if (this._searchTerm === "") return <></>;
- renderOptions = (): JSX.Element[] => {
- let allGroups: string[], searchTerm: string, results: string[], exactFound: boolean;
- if (this._searchTerm !== "") {
- allGroups = Array.from(LinkManager.Instance.groupMetadataKeys.keys());
- searchTerm = this._searchTerm.toUpperCase();
- results = allGroups.filter(group => group.toUpperCase().indexOf(searchTerm) > -1);
- exactFound = results.findIndex(group => group.toUpperCase() === searchTerm) > -1;
- } else {
- results = [];
- exactFound = false;
- }
+ let allGroupTypes = Array.from(LinkManager.Instance.groupMetadataKeys.keys());
+ let groupOptions = allGroupTypes.filter(groupType => groupType.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
+ let exactFound = groupOptions.findIndex(groupType => groupType.toUpperCase() === this._searchTerm.toUpperCase()) > -1;
- let options = [];
- results.forEach(result => {
- options.push(<div key={result} className="linkEditor-option"
- onClick={() => { this.props.setGroup(this.props.groupId, result); this.setGroupType(result); this.setSearchTerm(""); }}>{result}</div>);
+ let options = groupOptions.map(groupType => {
+ return <div key={groupType} className="linkEditor-option"
+ onClick={() => { this.props.setGroup(this.props.groupId, groupType); this.setGroupType(groupType); this.setSearchTerm(""); }}>{groupType}</div>;
});
+ // if search term does not already exist as a group type, give option to create new group type
if (!exactFound && this._searchTerm !== "") {
options.push(<div key={""} className="linkEditor-option"
onClick={() => { this.createGroup(this._searchTerm); this.setGroupType(this._searchTerm); this.setSearchTerm(""); }}>Define new "{this._searchTerm}" relationship</div>);
@@ -81,57 +72,66 @@ class LinkGroupsDropdown extends React.Component<{ groupId: string, groupType: s
}
-
+interface LinkMetadataEditorProps {
+ groupType: string;
+ mdDoc: Doc;
+ mdKey: string;
+ mdValue: string;
+}
@observer
-class LinkMetadataEditor extends React.Component<{ groupType: string, mdDoc: Doc, mdKey: string, mdValue: string }> {
+class LinkMetadataEditor extends React.Component<LinkMetadataEditorProps> {
@observable private _key: string = this.props.mdKey;
@observable private _value: string = this.props.mdValue;
+ @observable private _keyError: boolean = false;
@action
- editMetadataKey = (value: string): void => {
- // TODO: check that metadata doesnt already exist in group
+ setMetadataKey = (value: string): void => {
let groupMdKeys = new Array(...LinkManager.Instance.groupMetadataKeys.get(this.props.groupType)!);
- if (groupMdKeys) {
- let index = groupMdKeys.indexOf(this._key);
- if (index > -1) {
- groupMdKeys[index] = value;
- }
- else {
- console.log("OLD KEY WAS NOT FOUND", ...groupMdKeys);
- }
+
+ // don't allow user to create existing key
+ let newIndex = groupMdKeys.findIndex(key => key.toUpperCase() === value.toUpperCase());
+ if (newIndex > -1) {
+ this._keyError = true;
+ this._key = value;
+ return;
+ } else {
+ this._keyError = false;
}
+ // set new value for key
+ let currIndex = groupMdKeys.findIndex(key => key.toUpperCase() === this._key.toUpperCase());
+ if (currIndex === -1) console.error("LinkMetadataEditor: key was not found");
+ groupMdKeys[currIndex] = value;
+
this._key = value;
LinkManager.Instance.groupMetadataKeys.set(this.props.groupType, groupMdKeys);
}
@action
- editMetadataValue = (value: string): void => {
- this.props.mdDoc[this._key] = value;
- this._value = value;
+ setMetadataValue = (value: string): void => {
+ if (!this._keyError) {
+ this._value = value;
+ this.props.mdDoc[this._key] = value;
+ }
}
@action
removeMetadata = (): void => {
let groupMdKeys = new Array(...LinkManager.Instance.groupMetadataKeys.get(this.props.groupType)!);
- if (groupMdKeys) {
- let index = groupMdKeys.indexOf(this._key);
- if (index > -1) {
- groupMdKeys.splice(index, 1);
- }
- else {
- console.log("OLD KEY WAS NOT FOUND", ...groupMdKeys);
- }
- }
- this._key = "";
+
+ let index = groupMdKeys.findIndex(key => key.toUpperCase() === this._key.toUpperCase());
+ if (index === -1) console.error("LinkMetadataEditor: key was not found");
+ groupMdKeys.splice(index, 1);
+
LinkManager.Instance.groupMetadataKeys.set(this.props.groupType, groupMdKeys);
+ this._key = "";
}
render() {
return (
<div className="linkEditor-metadata-row">
- <input type="text" value={this._key} placeholder="key" onChange={e => this.editMetadataKey(e.target.value)}></input>:
- <input type="text" value={this._value} placeholder="value" onChange={e => this.editMetadataValue(e.target.value)}></input>
+ <input className={this._keyError ? "linkEditor-error" : ""} type="text" value={this._key} placeholder="key" onChange={e => this.setMetadataKey(e.target.value)}></input>:
+ <input type="text" value={this._value} placeholder="value" onChange={e => this.setMetadataValue(e.target.value)}></input>
<button onClick={() => this.removeMetadata()}>x</button>
</div>
);
@@ -144,175 +144,127 @@ interface LinkEditorProps {
linkDoc: Doc;
showLinks: () => void;
}
-
@observer
export class LinkEditor extends React.Component<LinkEditorProps> {
- @observable private _groups: Map<string, Doc> = new Map(); // map of temp group id to the corresponding group doc
+ // map of temporary group id to the corresponding group doc
+ @observable private _groups: Map<string, Doc> = new Map();
constructor(props: LinkEditorProps) {
super(props);
let groups = new Map<string, Doc>();
- let groupList = (Doc.AreProtosEqual(props.sourceDoc, Cast(props.linkDoc.anchor1, Doc, new Doc))) ?
- Cast(props.linkDoc.anchor1Groups, listSpec(Doc), []) : Cast(props.linkDoc.anchor2Groups, listSpec(Doc), []);
+ let groupList = LinkManager.Instance.getAnchorGroups(props.linkDoc, props.sourceDoc);
groupList.forEach(groupDoc => {
- if (groupDoc instanceof Doc) {
- let id = Utils.GenerateGuid();
- groups.set(id, groupDoc);
- } else {
- // promise doc
- }
+ let id = Utils.GenerateGuid();
+ groups.set(id, groupDoc);
});
this._groups = groups;
}
@action
addGroup = (): void => {
- console.log("before adding", ...Array.from(this._groups.keys()));
-
// new group only gets added if there is not already a group with type "new group"
let index = Array.from(this._groups.values()).findIndex(groupDoc => {
return groupDoc.type === "New Group";
});
- if (index === -1) {
- // create new document for group
- let mdDoc = Docs.TextDocument();
- mdDoc.proto!.anchor1 = this.props.sourceDoc.title;
- mdDoc.proto!.anchor2 = LinkUtils.findOppositeAnchor(this.props.linkDoc, this.props.sourceDoc).title;
+ if (index > -1) return;
- let groupDoc = Docs.TextDocument();
- groupDoc.proto!.type = "New Group";
- groupDoc.proto!.metadata = mdDoc;
+ // create new metadata document for group
+ let mdDoc = Docs.TextDocument();
+ mdDoc.proto!.anchor1 = this.props.sourceDoc.title;
+ mdDoc.proto!.anchor2 = LinkManager.Instance.findOppositeAnchor(this.props.linkDoc, this.props.sourceDoc).title;
- this._groups.set(Utils.GenerateGuid(), groupDoc);
+ // create new group document
+ let groupDoc = Docs.TextDocument();
+ groupDoc.proto!.type = "New Group";
+ groupDoc.proto!.metadata = mdDoc;
- let linkDoc = this.props.linkDoc.proto ? this.props.linkDoc.proto : this.props.linkDoc;
- LinkUtils.setAnchorGroups(linkDoc, this.props.sourceDoc, Array.from(this._groups.values()));
- }
+ this._groups.set(Utils.GenerateGuid(), groupDoc);
-
- // console.log("set anchor groups for", this.props.sourceDoc["title"]);
- console.log("after adding", ...Array.from(this._groups.keys()));
+ let linkDoc = this.props.linkDoc.proto ? this.props.linkDoc.proto : this.props.linkDoc;
+ LinkManager.Instance.setAnchorGroups(linkDoc, this.props.sourceDoc, Array.from(this._groups.values()));
}
@action
setGroupType = (groupId: string, groupType: string): void => {
- console.log("setting for ", groupId);
- // let linkDoc = this.props.linkDoc.proto ? this.props.linkDoc.proto : this.props.linkDoc;
let groupDoc = this._groups.get(groupId);
if (groupDoc) {
- console.log("found group doc");
groupDoc.proto!.type = groupType;
-
this._groups.set(groupId, groupDoc);
-
-
- LinkUtils.setAnchorGroups(this.props.linkDoc, this.props.sourceDoc, Array.from(this._groups.values()));
- console.log("set", Array.from(this._groups.values()).length);
+ LinkManager.Instance.setAnchorGroups(this.props.linkDoc, this.props.sourceDoc, Array.from(this._groups.values()));
}
-
- let anchor1groups: string[] = [];
- Cast(this.props.linkDoc.anchor1Groups, listSpec(Doc), []).forEach(doc => {
- if (doc instanceof Doc) {
- anchor1groups.push(StrCast(doc.proto!.type));
- } else {
- console.log("promise");
- }
- });
- let anchor2groups: string[] = [];
- Cast(this.props.linkDoc.anchor2Groups, listSpec(Doc), []).forEach(doc => {
- if (doc instanceof Doc) {
- anchor2groups.push(StrCast(doc.proto!.type));
- } else {
- console.log("promise");
- }
- });
- console.log("groups for anchors; anchor1: [", ...anchor1groups, "] ; anchor2: [", ...anchor2groups, "]");
}
- removeGroupFromLink = (groupId: string, groupType: string) => {
- // this._groups.delete(groupId);
+ removeGroupFromLink = (groupId: string, groupType: string): void => {
let groupDoc = this._groups.get(groupId);
- if (groupDoc) {
- LinkUtils.removeGroupFromAnchor(this.props.linkDoc, this.props.sourceDoc, groupType);
- this._groups.delete(groupId);
- }
- // LinkUtils.setAnchorGroups(this.props.linkDoc, this.props.sourceDoc, Array.from(this._groups.values()));
- console.log("\nremoved", groupId, "remaining", ...Array.from(this._groups.keys()), "\n");
+ if (!groupDoc) console.error("LinkEditor: group not found");
+ LinkManager.Instance.removeGroupFromAnchor(this.props.linkDoc, this.props.sourceDoc, groupType);
+ this._groups.delete(groupId);
}
- deleteGroup = (groupId: string, groupType: string) => {
+ deleteGroup = (groupId: string, groupType: string): void => {
let groupDoc = this._groups.get(groupId);
- if (groupDoc) {
- LinkManager.Instance.deleteGroup(groupType);
- this._groups.delete(groupId);
- }
+ if (!groupDoc) console.error("LinkEditor: group not found");
+ LinkManager.Instance.deleteGroup(groupType);
+ this._groups.delete(groupId);
}
- copyGroup = (groupId: string, groupType: string) => {
- let oppAnchor = LinkUtils.findOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
- let groupList = (Doc.AreProtosEqual(oppAnchor, Cast(this.props.linkDoc.anchor1, Doc, new Doc))) ?
- Cast(this.props.linkDoc.anchor1Groups, listSpec(Doc), []) : Cast(this.props.linkDoc.anchor2Groups, listSpec(Doc), []);
- // if group already exists on opposite anchor, copy value
- let index = groupList.findIndex(groupDoc => {
- if (groupDoc instanceof Doc) {
- return StrCast(groupDoc.type) === groupType;
- } else {
- return false;
- }
- });
- // TODO: clean
- // if (index > 0) {
- // let thisGroupDoc = this._groups.get(groupId);
- // let oppGroupDoc = groupList[index];
- // let keys = LinkManager.Instance.allGroups.get(groupType);
- // if (keys) {
- // keys.forEach(key => {
- // if (thisGroupDoc && oppGroupDoc instanceof Doc) { // TODO: clean
- // let val = thisGroupDoc[key] === undefined ? "" : StrCast(thisGroupDoc[key]);
- // oppGroupDoc[key] = val;
- // }
- // // mdDoc[key] === undefined) ? "" : StrCast(mdDoc[key])
- // // oppGroupDoc[key] = thisGroupDoc[key];
- // })
- // }
- // // LinkUtils.setAnchorGroups(this.props.linkDoc, oppAnchor, [oppGroupDoc]);
- // } else {
- let thisGroupDoc = this._groups.get(groupId);
- let thisMdDoc = Cast(thisGroupDoc!.metadata, Doc, new Doc);
- let newGroupDoc = Docs.TextDocument();
- let newMdDoc = Docs.TextDocument();
- newMdDoc.proto!.anchor1 = StrCast(thisMdDoc.anchor2);
- newMdDoc.proto!.anchor2 = StrCast(thisMdDoc.anchor1);
+ copyGroup = (groupId: string, groupType: string): void => {
+ let sourceGroupDoc = this._groups.get(groupId);
+ let sourceMdDoc = Cast(sourceGroupDoc!.metadata, Doc, new Doc);
+ let destDoc = LinkManager.Instance.findOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
+ let destGroupList = LinkManager.Instance.getAnchorGroups(this.props.linkDoc, destDoc);
let keys = LinkManager.Instance.groupMetadataKeys.get(groupType);
+
+ // create new metadata doc with copied kvp
+ let destMdDoc = Docs.TextDocument();
+ destMdDoc.proto!.anchor1 = StrCast(sourceMdDoc.anchor2);
+ destMdDoc.proto!.anchor2 = StrCast(sourceMdDoc.anchor1);
if (keys) {
keys.forEach(key => {
- if (thisGroupDoc) { // TODO: clean
- let val = thisMdDoc[key] === undefined ? "" : StrCast(thisMdDoc[key]);
- newMdDoc[key] = val;
- }
- // mdDoc[key] === undefined) ? "" : StrCast(mdDoc[key])
- // oppGroupDoc[key] = thisGroupDoc[key];
+ let val = sourceMdDoc[key] === undefined ? "" : StrCast(sourceMdDoc[key]);
+ destMdDoc[key] = val;
});
}
- newGroupDoc.proto!.type = groupType;
- newGroupDoc.proto!.metadata = newMdDoc;
- LinkUtils.setAnchorGroups(this.props.linkDoc, oppAnchor, [newGroupDoc]); // TODO: fix to append to list
- // }
+ // create new group doc with new metadata doc
+ let destGroupDoc = Docs.TextDocument();
+ destGroupDoc.proto!.type = groupType;
+ destGroupDoc.proto!.metadata = destMdDoc;
- // else create group on opposite anchor
+ // if group does not already exist on opposite anchor, create group doc
+ let index = destGroupList.findIndex(groupDoc => { StrCast(groupDoc.type).toUpperCase() === groupType.toUpperCase(); });
+ if (index > -1) {
+ destGroupList[index] = destGroupDoc;
+ } else {
+ destGroupList.push(destGroupDoc);
+ }
+
+ LinkManager.Instance.setAnchorGroups(this.props.linkDoc, destDoc, destGroupList);
+ }
+
+ viewGroupAsTable = (groupId: string, groupType: string): JSX.Element => {
+ let keys = LinkManager.Instance.groupMetadataKeys.get(groupType);
+ let groupDoc = this._groups.get(groupId);
+ if (keys && groupDoc) {
+ let docs: Doc[] = LinkManager.Instance.findAllMetadataDocsInGroup(groupType);
+ let createTable = action(() => Docs.SchemaDocument(["anchor1", "anchor2", ...keys!], docs, { width: 200, height: 200, title: groupType + " table" }));
+ let ref = React.createRef<HTMLDivElement>();
+ return <div className="linkEditor-groupOpts" ref={ref}><button onPointerDown={SetupDrag(ref, createTable)}><FontAwesomeIcon icon="table" size="sm" /></button></div>;
+ } else {
+ return <button className="linkEditor-groupOpts" disabled><FontAwesomeIcon icon="table" size="sm" /></button>;
+ }
}
- renderGroup(groupId: string, groupDoc: Doc) {
+ renderGroup = (groupId: string, groupDoc: Doc): JSX.Element => {
let type = StrCast(groupDoc.type);
if ((type && LinkManager.Instance.groupMetadataKeys.get(type)) || type === "New Group") {
return (
<div key={groupId} className="linkEditor-group">
<div className="linkEditor-group-row">
<p className="linkEditor-group-row-label">type:</p>
- <LinkGroupsDropdown groupId={groupId} groupType={StrCast(groupDoc.proto!.type)} setGroup={this.setGroupType} />
+ <GroupTypesDropdown groupId={groupId} groupType={StrCast(groupDoc.proto!.type)} setGroup={this.setGroupType} />
</div>
{this.renderMetadata(groupId)}
<div className="linkEditor-group-buttons">
@@ -330,35 +282,20 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
}
}
- viewGroupAsTable(groupId: string, groupType: string) {
- let keys = LinkManager.Instance.groupMetadataKeys.get(groupType);
- let groupDoc = this._groups.get(groupId);
- if (keys && groupDoc) {
- console.log("keys:", ...keys);
- let docs: Doc[] = LinkManager.Instance.findMetadataInGroup(groupType);
- let createTable = action(() => Docs.SchemaDocument(["anchor1", "anchor2", ...keys!], docs, { width: 200, height: 200, title: groupType + " table" }));
- let ref = React.createRef<HTMLDivElement>();
- return <div className="linkEditor-groupOpts" ref={ref}><button onPointerDown={SetupDrag(ref, createTable)}><FontAwesomeIcon icon="table" size="sm" /></button></div>;
- } else {
- return <button className="linkEditor-groupOpts" disabled><FontAwesomeIcon icon="table" size="sm" /></button>;
- }
- }
-
@action
addMetadata = (groupType: string): void => {
let mdKeys = LinkManager.Instance.groupMetadataKeys.get(groupType);
if (mdKeys) {
- if (mdKeys.indexOf("new key") === -1) {
- mdKeys.push("new key");
- }
+ // only add "new key" if there is no other key with value "new key"; prevents spamming
+ if (mdKeys.indexOf("new key") === -1) mdKeys.push("new key");
} else {
mdKeys = ["new key"];
}
LinkManager.Instance.groupMetadataKeys.set(groupType, mdKeys);
}
- renderMetadata(groupId: string) {
+ renderMetadata = (groupId: string): JSX.Element[] => {
let metadata: Array<JSX.Element> = [];
let groupDoc = this._groups.get(groupId);
if (groupDoc) {
@@ -377,7 +314,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
}
render() {
- let destination = LinkUtils.findOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
+ let destination = LinkManager.Instance.findOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
let groups: Array<JSX.Element> = [];
this._groups.forEach((groupDoc, groupId) => {
diff --git a/src/client/views/nodes/LinkMenu.scss b/src/client/views/nodes/LinkMenu.scss
index 7e031b897..09a830c9e 100644
--- a/src/client/views/nodes/LinkMenu.scss
+++ b/src/client/views/nodes/LinkMenu.scss
@@ -1,84 +1,14 @@
@import "../globalCssVariables";
-#linkMenu-container {
+.linkMenu {
width: 100%;
height: auto;
- display: flex;
- flex-direction: column;
}
-#linkMenu-searchBar {
- width: 100%;
- padding: 5px;
- margin-bottom: 10px;
- font-size: 12px;
- border: 1px solid #bababa;
-}
-
-#linkMenu-list {
- margin-top: 5px;
- width: 100%;
- height: 100px;
+.linkMenu-list {
+ max-height: 200px;
overflow-y: scroll;
}
-.link-menu-group {
- .link-menu-item {
- border-top: 0.5px solid $light-color-secondary;
- padding: 6px;
- position: relative;
- display: flex;
-
- .link-menu-item-content {
- width: 100%;
- }
- &:last-child {
- border-bottom: 0.5px solid $light-color-secondary;
- }
- &:hover .link-menu-item-buttons {
- display: flex;
- }
- &:hover .link-menu-item-content {
- width: calc(100% - 42px);
- }
- }
- .link-menu-item-buttons {
- display: none;
- position: absolute;
- top: 50%;
- right: 0;
- transform: translateY(-50%);
-
- .button {
- width: 20px;
- height: 20px;
- margin: 0;
- margin-right: 6px;
- border-radius: 50%;
- cursor: pointer;
- pointer-events: auto;
- background-color: $dark-color;
- color: $light-color;
- font-size: 65%;
- transition: transform 0.2s;
- text-align: center;
- position: relative;
-
- .fa-icon {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- }
-
- &:last-child {
- margin-right: 0;
- }
- &:hover {
- background: $main-accent;
- }
- }
- }
-}
diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx
index 47bd6c3eb..ebca54c92 100644
--- a/src/client/views/nodes/LinkMenu.tsx
+++ b/src/client/views/nodes/LinkMenu.tsx
@@ -6,12 +6,8 @@ import { LinkEditor } from "./LinkEditor";
import './LinkMenu.scss';
import React = require("react");
import { Doc, DocListCast } from "../../../new_fields/Doc";
-import { Cast, FieldValue, StrCast } from "../../../new_fields/Types";
import { Id } from "../../../new_fields/FieldSymbols";
import { LinkManager, LinkUtils } from "../../util/LinkManager";
-import { number, string } from "prop-types";
-import { listSpec } from "../../../new_fields/Schema";
-import { Utils } from "../../../Utils";
interface Props {
docView: DocumentView;
@@ -23,57 +19,42 @@ export class LinkMenu extends React.Component<Props> {
@observable private _editingLink?: Doc;
- // renderLinkItems(links: Doc[], key: string, type: string) {
- // return links.map(link => {
- // let doc = FieldValue(Cast(link[key], Doc));
- // if (doc) {
- // return <LinkBox key={doc[Id]} linkDoc={link} linkName={StrCast(link.title)} pairedDoc={doc} showEditor={action(() => this._editingLink = link)} type={type} />;
- // }
- // });
- // }
-
- renderGroup(links: Doc[]) {
+ renderGroup = (group: Doc[]): Array<JSX.Element> => {
let source = this.props.docView.Document;
- return links.map(link => {
- let destination = LinkUtils.findOppositeAnchor(link, source);
- let doc = FieldValue(Cast(destination, Doc));
- if (doc) {
- return <LinkBox key={doc[Id] + source[Id]} linkDoc={link} linkName={StrCast(destination.title)} pairedDoc={doc} showEditor={action(() => this._editingLink = link)} type={""} />;
- }
+ return group.map(linkDoc => {
+ let destination = LinkUtils.findOppositeAnchor(linkDoc, source);
+ return <LinkBox key={destination[Id] + source[Id]} linkDoc={linkDoc} sourceDoc={source} destinationDoc={destination} showEditor={action(() => this._editingLink = linkDoc)} />;
});
}
- renderLinks = (links: Map<string, Array<Doc>>): Array<JSX.Element> => {
+ renderAllGroups = (groups: Map<string, Array<Doc>>): Array<JSX.Element> => {
let linkItems: Array<JSX.Element> = [];
-
- links.forEach((links, group) => {
+ groups.forEach((group, groupType) => {
linkItems.push(
- <div key={group} className="link-menu-group">
- <p className="link-menu-group-name">{group}:</p>
+ <div key={groupType} className="link-menu-group">
+ <p className="link-menu-group-name">{groupType}:</p>
<div className="link-menu-group-wrapper">
- {this.renderGroup(links)}
+ {this.renderGroup(group)}
</div>
</div>
- )
+ );
});
- if (linkItems.length === 0) {
- linkItems.push(<p key="">no links have been created yet</p>);
- }
+ // source doc has no links
+ if (linkItems.length === 0) linkItems.push(<p key="">No links have been created yet. Drag the linking button onto another document to create a link.</p>);
return linkItems;
}
render() {
- let related: Map<string, Doc[]> = LinkManager.Instance.findRelatedGroupedLinks(this.props.docView.props.Document);
+ let sourceDoc = this.props.docView.props.Document;
+ let groups: Map<string, Doc[]> = LinkManager.Instance.findRelatedGroupedLinks(sourceDoc);
if (this._editingLink === undefined) {
return (
- <div id="linkMenu-container">
+ <div className="linkMenu">
{/* <input id="linkMenu-searchBar" type="text" placeholder="Search..."></input> */}
- <div id="linkMenu-list">
- {/* {this.renderLinkItems(linkTo, "linkedTo", "Destination: ")}
- {this.renderLinkItems(linkFrom, "linkedFrom", "Source: ")} */}
- {this.renderLinks(related)}
+ <div className="linkMenu-list">
+ {this.renderAllGroups(groups)}
</div>
</div>
);
@@ -82,6 +63,5 @@ export class LinkMenu extends React.Component<Props> {
<LinkEditor sourceDoc={this.props.docView.props.Document} linkDoc={this._editingLink} showLinks={action(() => this._editingLink = undefined)}></LinkEditor>
);
}
-
}
} \ No newline at end of file