From af380979349308077e13fc12a2d09255b7f05f28 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 23 Jan 2024 16:11:42 -0500
Subject: reorganization of DocumentView, DocumentViewInternal and FieldView
 methods and props. fix for selection bug after following a link.  migrating
 to use [DocData] instad of GetProto()

---
 src/client/views/search/SearchBox.tsx | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

(limited to 'src/client/views/search/SearchBox.tsx')

diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 4d29573d4..5dc4f5550 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -3,7 +3,7 @@ import { action, computed, makeObservable, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, DocListCastAsync, Field } from '../../../fields/Doc';
-import { DirectLinks } from '../../../fields/DocSymbols';
+import { DirectLinks, DocData } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { DocCast, StrCast } from '../../../fields/Types';
 import { DocumentType } from '../../documents/DocumentTypes';
@@ -58,7 +58,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
     /**
      * This is the constructor for the SearchBox class.
      */
-    constructor(props: any) {
+    constructor(props: SearchBoxProps) {
         super(props);
         makeObservable(this);
         SearchBox.Instance = this;
@@ -207,7 +207,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
         this._results.forEach((_, doc) => {
             this._pageRanks.set(doc, 1.0 / this._results.size);
 
-            if (Doc.GetProto(doc)[DirectLinks].size === 0) {
+            if (doc[DocData][DirectLinks].size === 0) {
                 this._linkedDocsOut.set(doc, new Set(this._results.keys()));
 
                 this._results.forEach((_, linkedDoc) => {
@@ -216,7 +216,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
             } else {
                 const linkedDocSet = new Set<Doc>();
 
-                Doc.GetProto(doc)[DirectLinks].forEach(link => {
+                doc[DocData][DirectLinks].forEach(link => {
                     const d1 = link?.link_anchor_1 as Doc;
                     const d2 = link?.link_anchor_2 as Doc;
                     if (doc === d1 && this._results.has(d2)) {
-- 
cgit v1.2.3-70-g09d2


From 0ea81ce3582c739078b86ea3bc1b58bdeb3fe839 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 27 Jan 2024 11:28:23 -0500
Subject: fixed searchBox

---
 src/client/util/SearchUtil.ts                                      | 3 ++-
 .../collections/collectionFreeForm/CollectionFreeFormView.tsx      | 2 +-
 src/client/views/search/SearchBox.tsx                              | 7 ++-----
 3 files changed, 5 insertions(+), 7 deletions(-)

(limited to 'src/client/views/search/SearchBox.tsx')

diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index 2cc64f415..68c981399 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -1,3 +1,4 @@
+import { ObservableMap } from 'mobx';
 import { Doc, DocListCast, Field, Opt } from '../../fields/Doc';
 import { Id } from '../../fields/FieldSymbols';
 import { StrCast } from '../../fields/Types';
@@ -44,7 +45,7 @@ export namespace SearchUtil {
         ];
         query = query.toLowerCase();
 
-        const results = new Map<Doc, string[]>();
+        const results = new ObservableMap<Doc, string[]>();
         if (collectionDoc) {
             const docs = DocListCast(collectionDoc[Doc.LayoutFieldKey(collectionDoc)]);
             const docIDs: String[] = [];
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index be19fc50f..d19c9f07d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1785,7 +1785,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         );
     }
     get pannableContents() {
-        this.incrementalRender();
+        setTimeout(this.incrementalRender);
         return (
             <CollectionFreeFormPannableContents
                 Document={this.Document}
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 5dc4f5550..c8caff9fa 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -55,9 +55,6 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
     @observable _deletedDocsStatus: boolean = false;
     @observable _onlyEmbeddings: boolean = true;
 
-    /**
-     * This is the constructor for the SearchBox class.
-     */
     constructor(props: SearchBoxProps) {
         super(props);
         makeObservable(this);
@@ -69,11 +66,11 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
      * the search panel, the search input box is automatically selected. This allows the user to
      * type in the search input box immediately, without needing clicking on it first.
      */
-    componentDidMount = action(() => {
+    componentDidMount() {
         if (this._inputRef.current) {
             this._inputRef.current.focus();
         }
-    });
+    }
 
     /**
      * This method is called when the SearchBox component is about to be unmounted. When the user
-- 
cgit v1.2.3-70-g09d2


From e17a812f8a8a2c389bf098f7a30c8326881d4dc6 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 27 Jan 2024 12:43:20 -0500
Subject: added searchable flag to docoption types. fixed searchbox scrolling
 and showing results. added search by key and exact match.

---
 src/client/documents/Documents.ts                  |   9 ++
 src/client/util/SearchUtil.ts                      |  55 +++-------
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   8 +-
 src/client/views/newlightbox/utils.ts              | 121 ++++++++++-----------
 src/client/views/nodes/LinkDocPreview.tsx          |   2 +-
 src/client/views/search/SearchBox.scss             |   1 +
 src/client/views/search/SearchBox.tsx              |  27 +++--
 7 files changed, 104 insertions(+), 119 deletions(-)

(limited to 'src/client/views/search/SearchBox.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index f1a0b37b3..ac418ecfe 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -81,6 +81,7 @@ export class FInfo {
         this.description = d;
         this.readOnly = readOnly ?? false;
     }
+    searchable = () => true;
 }
 class BoolInfo extends FInfo {
     fieldType? = 'boolean';
@@ -89,6 +90,7 @@ class BoolInfo extends FInfo {
         super(d);
         this.filterable = filterable;
     }
+    override searchable = () => false;
 }
 class NumInfo extends FInfo {
     fieldType? = 'number';
@@ -98,6 +100,7 @@ class NumInfo extends FInfo {
         this.values = values;
         this.filterable = filterable;
     }
+    override searchable = () => false;
 }
 class StrInfo extends FInfo {
     fieldType? = 'string';
@@ -116,34 +119,40 @@ class DocInfo extends FInfo {
         this.values = values;
         this.filterable = filterable;
     }
+    override searchable = () => false;
 }
 class DimInfo extends FInfo {
     fieldType? = 'enumeration';
     values? = [DimUnit.Pixel, DimUnit.Ratio];
     readOnly = false;
     filterable = false;
+    override searchable = () => false;
 }
 class PEInfo extends FInfo {
     fieldType? = 'enumeration';
     values? = ['all', 'none'];
     readOnly = false;
     filterable = false;
+    override searchable = () => false;
 }
 class DAInfo extends FInfo {
     fieldType? = 'enumeration';
     values? = ['embed', 'copy', 'move', 'same', 'proto', 'none'];
     readOnly = false;
     filterable = false;
+    override searchable = () => false;
 }
 class CTypeInfo extends FInfo {
     fieldType? = 'enumeration';
     values? = Array.from(Object.keys(CollectionViewType));
     readOnly = false;
     filterable = false;
+    override searchable = () => false;
 }
 class DTypeInfo extends FInfo {
     fieldType? = 'enumeration';
     values? = Array.from(Object.keys(DocumentType));
+    override searchable = () => false;
 }
 class DateInfo extends FInfo {
     fieldType? = 'date';
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index 68c981399..218667d3e 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -3,47 +3,21 @@ import { Doc, DocListCast, Field, Opt } from '../../fields/Doc';
 import { Id } from '../../fields/FieldSymbols';
 import { StrCast } from '../../fields/Types';
 import { DocumentType } from '../documents/DocumentTypes';
+import { DocOptions, FInfo } from '../documents/Documents';
 
 export namespace SearchUtil {
     export type HighlightingResult = { [id: string]: { [key: string]: string[] } };
 
-    export function SearchCollection(collectionDoc: Opt<Doc>, query: string) {
+    export function SearchCollection(collectionDoc: Opt<Doc>, query: string, matchKeyNames: boolean) {
         const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
-        const blockedKeys = [
-            'x',
-            'y',
-            'proto',
-            'width',
-            'layout_autoHeight',
-            'acl-Override',
-            'acl-Guest',
-            'embedContainer',
-            'zIndex',
-            'height',
-            'text_scrollHeight',
-            'text_height',
-            'cloneFieldFilter',
-            'isDataDoc',
-            'text_annotations',
-            'dragFactory_count',
-            'text_noTemplate',
-            'proto_embeddings',
-            'isSystem',
-            'layout_fieldKey',
-            'isBaseProto',
-            'xMargin',
-            'yMargin',
-            'links',
-            'layout',
-            'layout_keyValue',
-            'layout_fitWidth',
-            'type_collection',
-            'title_custom',
-            'freeform_panX',
-            'freeform_panY',
-            'freeform_scale',
-        ];
-        query = query.toLowerCase();
+        const blockedKeys = matchKeyNames
+            ? []
+            : Object.entries(DocOptions)
+                  .filter(([key, info]: [string, FInfo]) => !info?.searchable())
+                  .map(([key]) => key);
+
+        const exact = query.startsWith('=');
+        query = query.toLowerCase().split('=').lastElement();
 
         const results = new ObservableMap<Doc, string[]>();
         if (collectionDoc) {
@@ -54,11 +28,10 @@ export namespace SearchUtil {
                 if (dtype && !blockedTypes.includes(dtype) && !docIDs.includes(doc[Id]) && depth >= 0) {
                     const hlights = new Set<string>();
                     SearchUtil.documentKeys(doc).forEach(
-                        key =>
-                            (Field.toString(doc[key] as Field) + Field.toScriptString(doc[key] as Field))
-                                .toLowerCase() //
-                                .includes(query) && hlights.add(key)
-                    );
+                        key => (val => (exact ? val === query.toLowerCase() : val.includes(query.toLowerCase())))(
+                            matchKeyNames ? key : Field.toString(doc[key] as Field)) 
+                        && hlights.add(key)
+                    ); // prettier-ignore
                     blockedKeys.forEach(key => hlights.delete(key));
 
                     if (Array.from(hlights.keys()).length > 0) {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index d19c9f07d..d3c196a60 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -304,10 +304,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     focus = (anchor: Doc, options: FocusViewOptions) => {
         if (this._lightboxDoc) return;
         if (anchor === this.Document) {
-            if (options.willZoomCentered && options.zoomScale) {
-                this.fitContentOnce();
-                options.didMove = true;
-            }
+            // if (options.willZoomCentered && options.zoomScale) {
+            //     this.fitContentOnce();
+            //     options.didMove = true;
+            // }
         }
         if (anchor.type !== DocumentType.CONFIG && !DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]).includes(anchor)) return;
         const xfToCollection = options?.docTransform ?? Transform.Identity();
diff --git a/src/client/views/newlightbox/utils.ts b/src/client/views/newlightbox/utils.ts
index 6016abca4..c879718e3 100644
--- a/src/client/views/newlightbox/utils.ts
+++ b/src/client/views/newlightbox/utils.ts
@@ -1,121 +1,120 @@
-import { DocumentType } from "../../documents/DocumentTypes";
-import { IRecommendation } from "./components";
+import { DocumentType } from '../../documents/DocumentTypes';
+import { IRecommendation } from './components';
 
 export interface IDocRequest {
-    id: string,
-    title: string,
-    text: string,
-    type: string
+    id: string;
+    title: string;
+    text: string;
+    type: string;
 }
 
 export const fetchRecommendations = async (src: string, query: string, docs?: IDocRequest[], dummy?: boolean) => {
-    console.log("[rec] making request")
+    console.log('[rec] making request');
     if (dummy) {
         return {
-            "recommendations": dummyRecs,
-            "keywords": dummyKeywords,
-            "num_recommendations": 4,
-            "max_x": 100,
-            "max_y": 100,
-            "min_x": 0,
-            "min_y": 0
-
+            recommendations: [], //dummyRecs,
+            keywords: dummyKeywords,
+            num_recommendations: 4,
+            max_x: 100,
+            max_y: 100,
+            min_x: 0,
+            min_y: 0,
         };
     }
     const response = await fetch('http://127.0.0.1:8000/recommend', {
         method: 'POST',
         headers: {
-            'Accept': 'application/json',
-            'Content-Type': 'application/json'
+            Accept: 'application/json',
+            'Content-Type': 'application/json',
         },
-        body: JSON.stringify({ 
-            "src": src,
-            "query": query,
-            "docs": docs
-        })
-    })
+        body: JSON.stringify({
+            src: src,
+            query: query,
+            docs: docs,
+        }),
+    });
     const data = await response.json();
-    
+
     return data;
-}
+};
 
 export const fetchKeywords = async (text: string, n: number, dummy?: boolean) => {
-    console.log("[fetchKeywords]")
+    console.log('[fetchKeywords]');
     if (dummy) {
         return {
-            "keywords": dummyKeywords
+            keywords: dummyKeywords,
         };
     }
     const response = await fetch('http://127.0.0.1:8000/keywords', {
         method: 'POST',
         headers: {
-            'Accept': 'application/json',
-            'Content-Type': 'application/json'
+            Accept: 'application/json',
+            'Content-Type': 'application/json',
         },
-        body: JSON.stringify({ 
-            "text": text,
-            "n": n
-        })
-    })
-    const data = await response.json()
+        body: JSON.stringify({
+            text: text,
+            n: n,
+        }),
+    });
+    const data = await response.json();
     return data;
-}
+};
 
 export const getType = (type: DocumentType | string) => {
-    switch(type) {
+    switch (type) {
         case DocumentType.AUDIO:
-            return "Audio"
+            return 'Audio';
         case DocumentType.VID:
-            return "Video"
+            return 'Video';
         case DocumentType.PDF:
-            return "PDF"
+            return 'PDF';
         case DocumentType.WEB:
-            return "Webpage"
-        case "YouTube":
-            return "Video"
-        case "HTML":
-            return "Webpage"
+            return 'Webpage';
+        case 'YouTube':
+            return 'Video';
+        case 'HTML':
+            return 'Webpage';
         default:
-            return "Unknown: " + type
+            return 'Unknown: ' + type;
     }
-}
+};
 
 const dummyRecs = {
-    "a": {
+    a: {
         title: 'Vannevar Bush - American Engineer',
-        previewUrl: 'https://cdn.britannica.com/98/23598-004-1E6A382E/Vannevar-Bush-Differential-Analyzer-1935.jpg', 
+        previewUrl: 'https://cdn.britannica.com/98/23598-004-1E6A382E/Vannevar-Bush-Differential-Analyzer-1935.jpg',
         type: 'web',
         distance: 2.3,
         source: 'www.britannica.com',
         related_concepts: ['vannevar bush', 'knowledge'],
         embedding: {
             x: 0,
-            y: 0
-        }
+            y: 0,
+        },
     },
-    "b": {
+    b: {
         title: "From Memex to hypertext: Vannevar Bush and the mind's machine",
         type: 'pdf',
         distance: 5.4,
         source: 'Google Scholar',
         related_concepts: ['memex', 'vannevar bush', 'hypertext'],
     },
-    "c": {
+    c: {
         title: 'How the hyperlink changed everything | Small Thing Big Idea, a TED series',
-        previewUrl: 'https://pi.tedcdn.com/r/talkstar-photos.s3.amazonaws.com/uploads/b17d043f-2642-4117-a913-52204505513f/MargaretGouldStewart_2018V-embed.jpg?u%5Br%5D=2&u%5Bs%5D=0.5&u%5Ba%5D=0.8&u%5Bt%5D=0.03&quality=82w=640', 
+        previewUrl: 'https://pi.tedcdn.com/r/talkstar-photos.s3.amazonaws.com/uploads/b17d043f-2642-4117-a913-52204505513f/MargaretGouldStewart_2018V-embed.jpg?u%5Br%5D=2&u%5Bs%5D=0.5&u%5Ba%5D=0.8&u%5Bt%5D=0.03&quality=82w=640',
         type: 'youtube',
         distance: 5.3,
         source: 'www.youtube.com',
-        related_concepts: ['User Control', 'Explanations']
+        related_concepts: ['User Control', 'Explanations'],
     },
-    "d": {
+    d: {
         title: 'Recommender Systems: Behind the Scenes of Machine Learning-Based Personalization',
-        previewUrl: 'https://sloanreview.mit.edu/wp-content/uploads/2018/10/MAG-Ransbotham-Ratings-Recommendations-1200X627-1200x627.jpg', 
+        previewUrl: 'https://sloanreview.mit.edu/wp-content/uploads/2018/10/MAG-Ransbotham-Ratings-Recommendations-1200X627-1200x627.jpg',
         type: 'pdf',
         distance: 9.3,
         source: 'www.altexsoft.com',
-        related_concepts: ['User Control', 'Explanations']
-    }
-}
+        related_concepts: ['User Control', 'Explanations'],
+    },
+};
 
-const dummyKeywords = ['user control', 'vannevar bush', 'hypermedia', 'hypertext']
\ No newline at end of file
+const dummyKeywords = ['user control', 'vannevar bush', 'hypermedia', 'hypertext'];
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 4b242649a..3f793b85e 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -184,7 +184,7 @@ export class LinkDocPreview extends ObservableReactComponent<LinkDocPreviewProps
             LinkFollower.FollowLink(this._linkDoc, this._linkSrc, false);
         } else if (this._props.hrefs?.length) {
             const webDoc =
-                Array.from(SearchUtil.SearchCollection(Doc.MyFilesystem, this._props.hrefs[0]).keys()).lastElement() ??
+                Array.from(SearchUtil.SearchCollection(Doc.MyFilesystem, this._props.hrefs[0], false).keys()).lastElement() ??
                 Docs.Create.WebDocument(this._props.hrefs[0], { title: this._props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, data_useCors: true });
             DocumentManager.Instance.showDocument(webDoc, {
                 openLocation: OpenWhere.lightbox,
diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss
index 09e459f7d..94e64b952 100644
--- a/src/client/views/search/SearchBox.scss
+++ b/src/client/views/search/SearchBox.scss
@@ -8,6 +8,7 @@
     background: none;
     z-index: 1000;
     padding: 0px;
+    overflow: auto;
     cursor: default;
 
     .searchBox-bar {
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index c8caff9fa..0b664beaa 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -162,12 +162,13 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
      * which the first letter is capitalized. This is used when displaying the type on the
      * right side of each search result.
      */
-    static formatType(type: String): String {
-        if (type === 'pdf') {
-            return 'PDF';
-        } else if (type === 'image') {
-            return 'Img';
-        }
+    static formatType(type: string, colType: string): String {
+        switch (type) {
+            case DocumentType.PDF : return 'PDF';
+            case DocumentType.IMG : return 'Img';
+            case DocumentType.RTF : return 'Rtf';
+            case DocumentType.COL : return 'Col:'+colType.substring(0,3);
+        } // prettier-ignore
 
         return type.charAt(0).toUpperCase() + type.substring(1, 3);
     }
@@ -183,7 +184,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
     @action
     searchCollection(query: string) {
         this._selectedResult = undefined;
-        this._results = SearchUtil.SearchCollection(CollectionDockingView.Instance?.Document, query);
+        this._results = SearchUtil.SearchCollection(CollectionDockingView.Instance?.Document, query, this._docTypeString === 'keys');
 
         this.computePageRanks();
     }
@@ -357,11 +358,11 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
      */
     @computed
     public get selectOptions() {
-        const selectValues = ['all', DocumentType.RTF, DocumentType.IMG, DocumentType.PDF, DocumentType.WEB, DocumentType.VID, DocumentType.AUDIO, DocumentType.COL];
+        const selectValues = ['all', DocumentType.RTF, DocumentType.IMG, DocumentType.PDF, DocumentType.WEB, DocumentType.VID, DocumentType.AUDIO, DocumentType.COL, 'keys'];
 
         return selectValues.map(value => (
             <option key={value} value={value}>
-                {SearchBox.formatType(value)}
+                {SearchBox.formatType(value, '')}
             </option>
         ));
     }
@@ -387,10 +388,10 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                 className += ' searchBox-results-scroll-view-result-selected';
             }
 
-            const formattedType = SearchBox.formatType(StrCast(result[0].type));
+            const formattedType = SearchBox.formatType(StrCast(result[0].type), StrCast(result[0].type_collection));
             const title = result[0].title;
 
-            if (this._docTypeString === 'all' || this._docTypeString === result[0].type) {
+            if (this._docTypeString === 'keys' || this._docTypeString === 'all' || this._docTypeString === result[0].type) {
                 validResults++;
                 resultsJSX.push(
                     <Tooltip key={result[0][Id]} placement={'right'} title={<div className="dash-tooltip">{title as string}</div>}>
@@ -412,7 +413,9 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                             }}
                             className={className}>
                             <div className="searchBox-result-title">{title as string}</div>
-                            <div className="searchBox-result-type">{formattedType}</div>
+                            <div className="searchBox-result-type" style={{ color: SettingsManager.userVariantColor }}>
+                                {formattedType}
+                            </div>
                             <div className="searchBox-result-keys" style={{ color: SettingsManager.userVariantColor }}>
                                 {result[1].join(', ')}
                             </div>
-- 
cgit v1.2.3-70-g09d2


From cf85ee4ea73985529a16321d671d893ddb862439 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 22 Feb 2024 09:33:38 -0500
Subject: fixed search to update after typing delay. fixed collection of tags
 to set container for embeddings

---
 src/client/views/nodes/DocumentView.tsx |  4 ++--
 src/client/views/search/SearchBox.tsx   | 10 +++++++---
 2 files changed, 9 insertions(+), 5 deletions(-)

(limited to 'src/client/views/search/SearchBox.tsx')

diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index e8b0fc4ba..d131f72d5 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1501,8 +1501,7 @@ ScriptingGlobals.add(function updateTagsCollection(collection: Doc) {
     const matchedDocs = matchedTags
         .filter(tagDoc => !Doc.AreProtosEqual(collection, tagDoc))
         .reduce((aset, tagDoc) => {
-            if (Array.from(aset).find(doc => Doc.AreProtosEqual(tagDoc, doc))) return aset;
-            let embedding = collectionDocs.find(doc => Doc.AreProtosEqual(tagDoc, doc));
+            let embedding = Array.from(aset).find(doc => Doc.AreProtosEqual(tagDoc, doc)) ?? collectionDocs.find(doc => Doc.AreProtosEqual(tagDoc, doc));
             if (!embedding) {
                 embedding = Doc.MakeEmbedding(tagDoc);
                 embedding.x = wid;
@@ -1511,6 +1510,7 @@ ScriptingGlobals.add(function updateTagsCollection(collection: Doc) {
                 wid += NumCast(tagDoc._width);
                 created = true;
             }
+            Doc.SetContainer(embedding, collection);
             aset.add(embedding);
             return aset;
         }, new Set<Doc>());
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 0b664beaa..9f153e86d 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -88,9 +88,11 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
      * (Note: There is no longer a need to press enter to submit a search. Any update to the input
      * causes a search to be submitted automatically.)
      */
+    _timeout: any = undefined;
     onInputChange = action((e: React.ChangeEvent<HTMLInputElement>) => {
         this._searchString = e.target.value;
-        this.submitSearch();
+        this._timeout && clearTimeout(this._timeout);
+        this._timeout = setTimeout(() => this.submitSearch(), 300);
     });
 
     /**
@@ -334,6 +336,8 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
      * brushes and highlights. All search matches are cleared as well.
      */
     resetSearch = action(() => {
+        this._timeout && clearTimeout(this._timeout);
+        this._timeout = undefined;
         this._results.forEach((_, doc) => {
             DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.('', undefined, true);
             Doc.UnBrushDoc(doc);
@@ -436,10 +440,10 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                         </select>
                     )}
                     <input
-                        defaultValue={''}
+                        defaultValue=""
                         autoComplete="off"
                         onChange={this.onInputChange}
-                        onKeyPress={e => {
+                        onKeyDown={e => {
                             e.key === 'Enter' ? this.submitSearch() : null;
                             e.stopPropagation();
                         }}
-- 
cgit v1.2.3-70-g09d2

