diff options
Diffstat (limited to 'src/client/util/LinkManager.ts')
-rw-r--r-- | src/client/util/LinkManager.ts | 90 |
1 files changed, 66 insertions, 24 deletions
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 8972bf705..56d5dce4e 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -1,12 +1,16 @@ -import { action, makeObservable, observable, observe, runInAction } from 'mobx'; +import { action, makeObservable, observable, observe } from 'mobx'; import { computedFn } from 'mobx-utils'; -import { Doc, DocListCast, DocListCastAsync, Field, Opt } from '../../fields/Doc'; +import * as rp from 'request-promise'; +import { ClientUtils } from '../../ClientUtils'; +import { Doc, DocListCast, DocListCastAsync, FieldType, Opt } from '../../fields/Doc'; import { DirectLinks, DocData } from '../../fields/DocSymbols'; import { FieldLoader } from '../../fields/FieldLoader'; +import { Id } from '../../fields/FieldSymbols'; import { List } from '../../fields/List'; import { ProxyField } from '../../fields/Proxy'; import { Cast, DocCast, PromiseValue, StrCast } from '../../fields/Types'; import { DocServer } from '../DocServer'; +import { DocumentType } from '../documents/DocumentTypes'; import { ScriptingGlobals } from './ScriptingGlobals'; /* * link doc: @@ -21,12 +25,13 @@ import { ScriptingGlobals } from './ScriptingGlobals'; * - user defined kvps */ export class LinkManager { + // eslint-disable-next-line no-use-before-define @observable static _instance: LinkManager; @observable.shallow userLinkDBs: Doc[] = []; @observable public currentLink: Opt<Doc> = undefined; @observable public currentLinkAnchor: Opt<Doc> = undefined; - public static get Instance() { - return LinkManager._instance; + public static get Instance(): LinkManager { + return Doc.UserDoc() ? LinkManager._instance ?? new LinkManager() : (undefined as any as LinkManager); } public static Links(doc: Doc | undefined) { @@ -42,9 +47,13 @@ export class LinkManager { this.userLinkDBs.push(linkDb); }; public static AutoKeywords = 'keywords:Usages'; - constructor() { + private constructor() { makeObservable(this); LinkManager._instance = this; + Doc.AddLink = this.addLink; + Doc.DeleteLink = this.deleteLink; + Doc.Links = LinkManager.Links; + Doc.getOppositeAnchor = LinkManager.getOppositeAnchor; this.createlink_relationshipLists(); // since this is an action, not a reaction, we get only one shot to add this link to the Anchor docs // Thus make sure all promised values are resolved from link -> link.proto -> link.link_anchor_[1,2] -> link.link_anchor_[1,2].proto @@ -56,7 +65,7 @@ export class LinkManager { Promise.all(lAnchs.map(lAnch => PromiseValue(lAnch?.proto as Doc))).then((lAnchProtos: Opt<Doc>[]) => Promise.all(lAnchProtos.map(lAnchProto => PromiseValue(lAnchProto?.proto as Doc))).then( link && - action(lAnchProtoProtos => { + action(() => { Doc.AddDocToList(Doc.UserDoc(), 'links', link); lAnchs[0]?.[DocData][DirectLinks].add(link); lAnchs[1]?.[DocData][DirectLinks].add(link); @@ -73,7 +82,7 @@ export class LinkManager { Promise.all([lproto?.link_anchor_1 as Doc, lproto?.link_anchor_2 as Doc].map(PromiseValue)).then((lAnchs: Opt<Doc>[]) => Promise.all(lAnchs.map(lAnch => PromiseValue(lAnch?.proto as Doc))).then((lAnchProtos: Opt<Doc>[]) => Promise.all(lAnchProtos.map(lAnchProto => PromiseValue(lAnchProto?.proto as Doc))).then( - action(lAnchProtoProtos => { + action(() => { link && lAnchs[0] && lAnchs[0][DocData][DirectLinks].delete(link); link && lAnchs[1] && lAnchs[1][DocData][DirectLinks].delete(link); }) @@ -84,7 +93,7 @@ export class LinkManager { ); const watchUserLinkDB = (userLinkDBDoc: Doc) => { - const toRealField = (field: Field) => (field instanceof ProxyField ? field.value : field); // see List.ts. data structure is not a simple list of Docs, but a list of ProxyField/Fields + const toRealField = (field: FieldType) => (field instanceof ProxyField ? field.value : field); // see List.ts. data structure is not a simple list of Docs, but a list of ProxyField/Fields if (userLinkDBDoc.data) { observe( userLinkDBDoc.data, @@ -95,7 +104,8 @@ export class LinkManager { (change as any).added.forEach((link: any) => addLinkToDoc(toRealField(link))); (change as any).removed.forEach((link: any) => remLinkFromDoc(toRealField(link))); break; - case 'update': //let oldValue = change.oldValue; + case 'update': // let oldValue = change.oldValue; + default: } }, true @@ -115,6 +125,8 @@ export class LinkManager { added?.forEach((link: any) => addLinkToDoc(toRealField(link))); removed?.forEach((link: any) => remLinkFromDoc(toRealField(link))); }); + break; + default: } }, true @@ -128,7 +140,8 @@ export class LinkManager { case 'splice': (change as any).added.forEach(watchUserLinkDB); break; - case 'update': //let oldValue = change.oldValue; + case 'update': // let oldValue = change.oldValue; + default: } }, true @@ -138,7 +151,7 @@ export class LinkManager { } public createlink_relationshipLists = () => { - //create new lists for link relations and their associated colors if the lists don't already exist + // create new lists for link relations and their associated colors if the lists don't already exist !Doc.UserDoc().link_relationshipList && (Doc.UserDoc().link_relationshipList = new List<string>()); !Doc.UserDoc().link_ColorList && (Doc.UserDoc().link_ColorList = new List<string>()); !Doc.UserDoc().link_relationshipSizes && (Doc.UserDoc().link_relationshipSizes = new List<number>()); @@ -148,7 +161,8 @@ export class LinkManager { Doc.AddDocToList(Doc.UserDoc(), 'links', linkDoc); if (!checkExists || !DocListCast(Doc.LinkDBDoc().data).includes(linkDoc)) { Doc.AddDocToList(Doc.LinkDBDoc(), 'data', linkDoc); - setTimeout(DocServer.UPDATE_SERVER_CACHE, 100); + // eslint-disable-next-line no-use-before-define + setTimeout(UPDATE_SERVER_CACHE, 100); } } public deleteLink(linkDoc: Doc) { @@ -188,9 +202,7 @@ export class LinkManager { ); }; - relatedLinker = computedFn(function relatedLinker(this: any, anchor: Doc): Doc[] { - return this.computedRelatedLinks(anchor, [anchor]); - }, true); + relatedLinker = computedFn((anchor: Doc): Doc[] => this.computedRelatedLinks(anchor, [anchor]), true); // returns map of group type to anchor's links in that group type public getRelatedGroupedLinks(anchor: Doc): Map<string, Array<Doc>> { @@ -198,7 +210,7 @@ export class LinkManager { this.relatedLinker(anchor).forEach(link => { if (link.link_relationship && link.link_relationship !== '-ungrouped-') { const relation = StrCast(link.link_relationship); - const anchorRelation = relation.indexOf(':') !== -1 ? relation.split(':')[Doc.AreProtosEqual(Cast(link.link_anchor_1, Doc, null), anchor) ? 0 : 1] : relation; + const anchorRelation: string = relation.indexOf(':') !== -1 ? relation.split(':')[Doc.AreProtosEqual(Cast(link.link_anchor_1, Doc, null), anchor) ? 0 : 1] : relation; const group = anchorGroups.get(anchorRelation); anchorGroups.set(anchorRelation, group ? [...group, link] : [link]); } else { @@ -229,18 +241,48 @@ export class LinkManager { if (Doc.AreProtosEqual(DocCast(anchor?.annotationOn, anchor), DocCast(a1?.annotationOn, a1))) return '1'; if (Doc.AreProtosEqual(DocCast(anchor?.annotationOn, anchor), DocCast(a2?.annotationOn, a2))) return '2'; if (Doc.AreProtosEqual(anchor, linkDoc)) return '0'; - - // const a1 = DocCast(linkDoc.link_anchor_1); - // const a2 = DocCast(linkDoc.link_anchor_2); - // if (linkDoc.link_matchEmbeddings) { - // return [a2, a2.annotationOn].includes(anchor) ? '2' : '1'; - // } - // if (Doc.AreProtosEqual(a2, anchor) || Doc.AreProtosEqual(a2.annotationOn as Doc, anchor)) return '2'; - // return Doc.AreProtosEqual(a1, anchor) || Doc.AreProtosEqual(a1.annotationOn as Doc, anchor) ? '1' : '2'; + return undefined; } } +let cacheDocumentIds = ''; // ; separate string of all documents ids in the user's working set (cached on the server) +export function UPDATE_SERVER_CACHE() { + const prototypes = Object.values(DocumentType) + .filter(type => type !== DocumentType.NONE) + .map(type => DocServer.GetCachedRefField(type + 'Proto')) + .filter(doc => doc instanceof Doc) + .map(doc => doc as Doc); + const references = new Set<Doc>(prototypes); + Doc.FindReferences(Doc.UserDoc(), references, undefined); + DocListCast(DocCast(Doc.UserDoc().myLinkDatabase).data).forEach(link => { + if (!references.has(DocCast(link.link_anchor_1)) && !references.has(DocCast(link.link_anchor_2))) { + Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myLinkDatabase), 'data', link); + Doc.AddDocToList(Doc.MyRecentlyClosed, undefined, link); + } + }); + LinkManager.Instance.userLinkDBs.forEach(linkDb => Doc.FindReferences(linkDb, references, undefined)); + const filtered = Array.from(references); + + const newCacheUpdate = filtered.map(doc => doc[Id]).join(';'); + if (newCacheUpdate === cacheDocumentIds) return; + cacheDocumentIds = newCacheUpdate; + + // print out cached docs + Doc.MyDockedBtns.linearView_IsOpen && console.log('Set cached docs = '); + const isFiltered = filtered.filter(doc => !Doc.IsSystem(doc)); + const strings = isFiltered.map(doc => StrCast(doc.title) + ' ' + (Doc.IsDataProto(doc) ? '(data)' : '(embedding)')); + Doc.MyDockedBtns.linearView_IsOpen && strings.sort().forEach((str, i) => console.log(i.toString() + ' ' + str)); + + rp.post(ClientUtils.prepend('/setCacheDocumentIds'), { + body: { + cacheDocumentIds, + }, + json: true, + }); +} + ScriptingGlobals.add( + // eslint-disable-next-line prefer-arrow-callback function links(doc: any) { return new List(LinkManager.Links(doc)); }, |