From 38a0f3f0b690599d72e52456ecfc14c081811e89 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 20 Apr 2020 19:05:05 -0400
Subject: fixed dragging off search result collection

---
 src/client/views/search/SearchBox.tsx | 19 +++++++------------
 1 file changed, 7 insertions(+), 12 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 0947bff8d..f332104fc 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -167,15 +167,7 @@ export class SearchBox extends React.Component<SearchProps> {
     }
 
     basicRequireWords(query: string): string {
-        const oldWords = query.split(" ");
-        const newWords: string[] = [];
-        oldWords.forEach(word => {
-            const newWrd = "+" + word;
-            newWords.push(newWrd);
-        });
-        query = newWords.join(" ");
-
-        return query;
+        return query.split(" ").join(" + ").replace(/ + /, "");
     }
 
     @action
@@ -316,10 +308,13 @@ export class SearchBox extends React.Component<SearchProps> {
 
     private get filterQuery() {
         const types = this.filterTypes;
-        const includeDeleted = this.getDataStatus() ? "" : " AND NOT deleted_b:true";
-        const includeIcons = this.getDataStatus() ? "" : " AND NOT type_t:fonticonbox";
+        const baseExpr = "NOT baseProto_b:true";
+        const includeDeleted = this.getDataStatus() ? "" : " NOT deleted_b:true";
+        const includeIcons = this.getDataStatus() ? "" : " NOT type_t:fonticonbox";
+        const typeExpr = !types ? "" : ` (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})`;
         // fq: type_t:collection OR {!join from=id to=proto_i}type_t:collection   q:text_t:hello
-        return "NOT baseProto_b:true" + includeDeleted + includeIcons + (types ? ` AND (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})` : "");
+        const query = [baseExpr, includeDeleted, includeIcons, typeExpr].join(" AND ").replace(/AND $/, "");
+        return query;
     }
 
     getDataStatus() { return this._deletedDocsStatus; }
-- 
cgit v1.2.3-70-g09d2


From a9b6fba3a742f95815e2664770079bebd3b87d5f Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 20 Apr 2020 22:34:29 -0400
Subject: fixed search to avoid server crashes by stripping off initial ?*+
 characters.  made search parameters persistent on queryBox

---
 src/client/documents/Documents.ts                  |  1 +
 src/client/util/SearchUtil.ts                      |  2 +-
 src/client/views/nodes/QueryBox.tsx                | 13 +++++--
 src/client/views/search/IconBar.tsx                |  4 +--
 src/client/views/search/SearchBox.tsx              | 40 +++++++++++-----------
 src/server/ApiManagers/SearchManager.ts            | 17 ++++-----
 .../authentication/models/current_user_utils.ts    |  1 +
 7 files changed, 42 insertions(+), 36 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index e3cc8ccfe..5ff8f29ec 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -140,6 +140,7 @@ export interface DocumentOptions {
     icon?: string;
     sourcePanel?: Doc; // panel to display in 'targetContainer' as the result of a button onClick script
     targetContainer?: Doc; // document whose proto will be set to 'panel' as the result of a onClick click script
+    searchFileTypes?: List<string>; // file types allowed in a search query
     strokeWidth?: number;
     treeViewPreventOpen?: boolean; // ignores the treeViewOpen Doc flag which allows a treeViewItem's expand/collapse state to be independent of other views of the same document in the tree view
     treeViewHideTitle?: boolean; // whether to hide the title of a tree view
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index 2026bf940..6501da34a 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -44,7 +44,7 @@ export namespace SearchUtil {
         const { ids, highlighting } = result;
 
         const txtresult = query !== "*" && JSON.parse(await rp.get(Utils.prepend("/textsearch"), {
-            qs: { ...options, q: query },
+            qs: { ...options, q: query.replace(/^[ \+\?\*\|]*/, "") }, // a leading '+' leads to a server crash since findInFiles doesn't handle regex failures
         }));
 
         const fileids = txtresult ? txtresult.ids : [];
diff --git a/src/client/views/nodes/QueryBox.tsx b/src/client/views/nodes/QueryBox.tsx
index 947167200..76885eada 100644
--- a/src/client/views/nodes/QueryBox.tsx
+++ b/src/client/views/nodes/QueryBox.tsx
@@ -3,13 +3,14 @@ import { IReactionDisposer } from "mobx";
 import { observer } from "mobx-react";
 import { documentSchema } from "../../../new_fields/documentSchemas";
 import { Id } from '../../../new_fields/FieldSymbols';
-import { makeInterface } from "../../../new_fields/Schema";
-import { StrCast } from "../../../new_fields/Types";
+import { makeInterface, listSpec } from "../../../new_fields/Schema";
+import { StrCast, Cast } from "../../../new_fields/Types";
 import { SelectionManager } from "../../util/SelectionManager";
 import { ViewBoxAnnotatableComponent } from '../DocComponent';
 import { SearchBox } from "../search/SearchBox";
 import { FieldView, FieldViewProps } from './FieldView';
 import "./QueryBox.scss";
+import { List } from "../../../new_fields/List";
 
 type QueryDocument = makeInterface<[typeof documentSchema]>;
 const QueryDocument = makeInterface(documentSchema);
@@ -28,7 +29,13 @@ export class QueryBox extends ViewBoxAnnotatableComponent<FieldViewProps, QueryD
     render() {
         const dragging = !SelectionManager.GetIsDragging() ? "" : "-dragging";
         return <div className={`queryBox${dragging}`} onWheel={(e) => e.stopPropagation()} >
-            <SearchBox id={this.props.Document[Id]} searchQuery={StrCast(this.dataDoc.searchQuery)} filterQquery={StrCast(this.dataDoc.filterQuery)} />
+            <SearchBox
+                id={this.props.Document[Id]}
+                setSearchQuery={q => this.dataDoc.searchQuery = q}
+                searchQuery={StrCast(this.dataDoc.searchQuery)}
+                setSearchFileTypes={q => this.dataDoc.searchFileTypes = new List<string>(q)}
+                searchFileTypes={Cast(this.dataDoc.searchFileTypes, listSpec("string"), [])}
+                filterQquery={StrCast(this.dataDoc.filterQuery)} />
         </div >;
     }
 }
\ No newline at end of file
diff --git a/src/client/views/search/IconBar.tsx b/src/client/views/search/IconBar.tsx
index 9cf5a9c87..9b7cf2fc6 100644
--- a/src/client/views/search/IconBar.tsx
+++ b/src/client/views/search/IconBar.tsx
@@ -25,7 +25,7 @@ library.add(faGlobeAsia);
 library.add(faBan);
 
 export interface IconBarProps {
-    setIcons: (icons: string[]) => {};
+    setIcons: (icons: string[]) => void;
 }
 
 
@@ -44,7 +44,7 @@ export class IconBar extends React.Component<IconBarProps> {
 
     @action.bound
     updateIcon(newArray: string[]) {
-    this._icons = newArray;
+        this._icons = newArray;
         this.props.setIcons?.(this._icons);
     }
 
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index f332104fc..b0a49f750 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -19,13 +19,17 @@ import { FieldView } from '../nodes/FieldView';
 import { DocumentType } from "../../documents/DocumentTypes";
 import { DocumentView } from '../nodes/DocumentView';
 import { SelectionManager } from '../../util/SelectionManager';
+import { listSpec } from '../../../new_fields/Schema';
 
 library.add(faTimes);
 
 export interface SearchProps {
     id: string;
-    searchQuery?: string;
+    searchQuery: string;
     filterQquery?: string;
+    setSearchQuery: (q: string) => {};
+    searchFileTypes: string[];
+    setSearchFileTypes: (types: string[]) => {}
 }
 
 export enum Keys {
@@ -37,7 +41,8 @@ export enum Keys {
 @observer
 export class SearchBox extends React.Component<SearchProps> {
 
-    @observable private _searchString: string = "";
+    private get _searchString() { return this.props.searchQuery; }
+    private set _searchString(value) { this.props.setSearchQuery(value); }
     @observable private _resultsOpen: boolean = false;
     @observable private _searchbarOpen: boolean = false;
     @observable private _results: [Doc, string[], string[]][] = [];
@@ -72,20 +77,16 @@ export class SearchBox extends React.Component<SearchProps> {
         this.resultsScrolled = this.resultsScrolled.bind(this);
     }
 
-    componentDidMount = () => {
+    componentDidMount = action(() => {
         if (this.inputRef.current) {
             this.inputRef.current.focus();
-            runInAction(() => this._searchbarOpen = true);
+            this._searchbarOpen = true;
         }
-        if (this.props.searchQuery && this.props.filterQquery) {
-            console.log(this.props.searchQuery);
-            const sq = this.props.searchQuery;
-            runInAction(() => {
-                this._searchString = sq;
-                this.submitSearch();
-            });
+        if (this.props.searchQuery) { // bcz: why was this here?    } && this.props.filterQquery) {
+            this._searchString = this.props.searchQuery;
+            this.submitSearch();
         }
-    }
+    })
 
 
     @action
@@ -133,7 +134,10 @@ export class SearchBox extends React.Component<SearchProps> {
     //this also serves as an indicator if the word status filter is applied
     @observable private _filterOpen: boolean = false;
     //if icons = all icons, then no icon filter is applied
-    @observable private _icons: string[] = this._allIcons;
+    get _icons() { return this.props.searchFileTypes; }
+    set _icons(value) {
+        this.props.setSearchFileTypes(value);
+    }
     //if all of these are true, no key filter is applied
     @observable private _titleFieldStatus: boolean = true;
     @observable private _authorFieldStatus: boolean = true;
@@ -206,12 +210,6 @@ export class SearchBox extends React.Component<SearchProps> {
         return this._icons.length === this._allIcons.length ? undefined : this._icons;
     }
 
-    @action.bound
-    updateIcon(newArray: string[]) { this._icons = newArray; }
-
-    @action.bound
-    getIcons(): string[] { return this._icons; }
-
     //TODO: basically all of this
     //gets all of the collections of all the docviews that are selected
     //if a collection is the only thing selected, search only in that collection (not its container)
@@ -648,7 +646,9 @@ export class SearchBox extends React.Component<SearchProps> {
                         <button className="filter-item" style={this._nodeStatus ? { background: "#aaaaa3" } : {}} onClick={this.handleNodeChange}>Nodes</button>
                     </div>
                     <div id={`node${this.props.id}`} className="filter-body" style={this._nodeStatus ? { borderTop: "grey 1px solid" } : { borderTop: "0px" }}>
-                        <IconBar setIcons={(icons: string[]) => this._icons = icons} />
+                        <IconBar setIcons={(icons: string[]) => {
+                            this._icons = icons;
+                        }} />
                     </div>
                     <div className="filter-key" id={`key${this.props.id}`} style={this._keyStatus ? { borderTop: "grey 1px solid" } : { borderTop: "0px" }}>
                         <div className="filter-keybar">
diff --git a/src/server/ApiManagers/SearchManager.ts b/src/server/ApiManagers/SearchManager.ts
index 9e1cc120d..753c31fcf 100644
--- a/src/server/ApiManagers/SearchManager.ts
+++ b/src/server/ApiManagers/SearchManager.ts
@@ -45,16 +45,13 @@ export class SearchManager extends ApiManager {
                     return;
                 }
                 const resObj: { ids: string[], numFound: number, lines: string[] } = { ids: [], numFound: 0, lines: [] };
-                try {
-                    const results = await findInFiles.find({ 'term': q, 'flags': 'ig' }, pathToDirectory(Directory.text), ".txt$");
-                    for (const result in results) {
-                        resObj.ids.push(path.basename(result, ".txt").replace(/upload_/, ""));
-                        resObj.lines.push(results[result].line);
-                        resObj.numFound++;
-                    }
-                }
-                catch (e) {
-                    console.error(e);
+                let results: any;
+                const dir = pathToDirectory(Directory.text);
+                results = await findInFiles.find({ 'term': q, 'flags': 'ig' }, dir, ".txt$");
+                for (const result in results) {
+                    resObj.ids.push(path.basename(result, ".txt").replace(/upload_/, ""));
+                    resObj.lines.push(results[result].line);
+                    resObj.numFound++;
                 }
                 res.send(resObj);
             }
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index e0ca5a468..3955f64fc 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -413,6 +413,7 @@ export class CurrentUserUtils {
                 _width: 50, _height: 25, title: "Search", fontSize: 10,
                 letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
                 sourcePanel: new PrefetchProxy(Docs.Create.QueryDocument({ title: "search stack", })) as any as Doc,
+                searchFileTypes: new List<string>([DocumentType.RTF, DocumentType.IMG, DocumentType.PDF, DocumentType.VID, DocumentType.WEB, DocumentType.SCRIPTING]),
                 targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc,
                 lockedPosition: true,
                 onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel")
-- 
cgit v1.2.3-70-g09d2

