From 88b06945c8a1fcb7bc518de878a4894de70dda94 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 22 Aug 2020 14:21:41 -0400
Subject: major overhaul of search to avoid writing anything to filtered
 documents and to make the UI work properly.

---
 src/client/views/collections/CollectionMenu.tsx | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

(limited to 'src/client/views/collections/CollectionMenu.tsx')

diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 388eda2b3..5580c32f2 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -131,7 +131,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
     _contentCommand = {
         params: ["target", "source"], title: "set content",
         script: "getProto(self.target).data = copyField(self.source);",
-        immediate: undoBatch((source: Doc[]) => Doc.GetProto(this.target).data = new List<Doc>(source)), // Doc.aliasDocs(source),
+        immediate: undoBatch((source: Doc[]) => Doc.GetProto(this.target).data = new List<Doc>(source)),
         initialize: emptyFunction,
     };
     _onClickCommand = {
@@ -180,12 +180,16 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
     };
     _saveFilterCommand = {
         params: ["target"], title: "save filter",
-        script: "self.target._docFilters = copyField(self['target-docFilters']);",
-        immediate: undoBatch((source: Doc[]) => this.target._docFilters = undefined),
-        initialize: (button: Doc) => { button['target-docFilters'] = this.target._docFilters instanceof ObjectField ? ObjectField.MakeCopy(this.target._docFilters as any as ObjectField) : ""; },
+        script: `self.target._docFilters = copyField(self['target-docFilters']); 
+                 self.target._searchFilterDocs = compareLists(self['target-searchFilterDocs'],self.target._searchFilterDocs) ? undefined: copyField(self['target-searchFilterDocs']);`,
+        immediate: undoBatch((source: Doc[]) => { this.target._docFilters = undefined; this.target._searchFilterDocs = undefined; }),
+        initialize: (button: Doc) => {
+            button['target-docFilters'] = this.target._docFilters instanceof ObjectField ? ObjectField.MakeCopy(this.target._docFilters as any as ObjectField) : undefined;
+            button['target-searchFilterDocs'] = this.target._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(this.target._searchFilterDocs as any as ObjectField) : undefined;
+        },
     };
 
-    @computed get _freeform_commands() { return Doc.UserDoc().noviceMode ? [this._viewCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; }
+    @computed get _freeform_commands() { return Doc.UserDoc().noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; }
     @computed get _stacking_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._contentCommand, this._templateCommand]; }
     @computed get _masonry_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._contentCommand, this._templateCommand]; }
     @computed get _schema_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._templateCommand, this._narrativeCommand]; }
-- 
cgit v1.2.3-70-g09d2


From ff5994377a80ec76c0138c5966f43a5bbce6e8b3 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 22 Aug 2020 19:44:02 -0400
Subject: more search cleanup.  searches over dashboards, not collections now. 
 fixed drag-off filters to still work with collections.

---
 src/Utils.ts                                       |   2 +-
 src/client/documents/Documents.ts                  |   1 +
 .../views/collections/CollectionDockingView.tsx    |  27 ++--
 src/client/views/collections/CollectionMenu.tsx    |   6 +-
 .../views/collections/CollectionSchemaCells.tsx    |  12 +-
 src/client/views/collections/CollectionSubView.tsx |   1 +
 src/client/views/collections/SchemaTable.tsx       | 153 ++++++---------------
 src/client/views/nodes/KeyValuePair.tsx            |   5 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |   2 +-
 src/client/views/search/SearchBox.tsx              | 135 +++++-------------
 src/fields/Doc.ts                                  |   6 +-
 src/fields/List.ts                                 |   2 +-
 12 files changed, 114 insertions(+), 238 deletions(-)

(limited to 'src/client/views/collections/CollectionMenu.tsx')

diff --git a/src/Utils.ts b/src/Utils.ts
index 3ff05104f..5b5a06839 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -422,7 +422,7 @@ export function returnEmptyString() { return ""; }
 
 export function returnEmptyFilter() { return [] as string[]; }
 
-export function returnEmptyDoclist() { return [] as Doc[]; }
+export function returnEmptyDoclist() { return [] as any[]; }
 
 export let emptyPath = [];
 
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 49da4f9eb..36712ab3e 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -873,6 +873,7 @@ export namespace DocUtils {
         }
 
         const filteredDocs = docFilters.length ? childDocs.filter(d => {
+            if (d.z) return true;
             for (const facetKey of Object.keys(filterFacets)) {
                 const facet = filterFacets[facetKey];
                 const satisfiesFacet = Object.keys(facet).some(value => {
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 58c40b1d4..6277fbb14 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -30,14 +30,14 @@ import { DocumentView } from "../nodes/DocumentView";
 import { PresBox } from '../nodes/PresBox';
 import "./CollectionDockingView.scss";
 import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
-import { SubCollectionViewProps } from "./CollectionSubView";
+import { SubCollectionViewProps, CollectionSubView } from "./CollectionSubView";
 import { CollectionViewType } from './CollectionView';
 import { DockingViewButtonSelector } from './ParentDocumentSelector';
 import React = require("react");
 const _global = (window /* browser */ || global /* node */) as any;
 
 @observer
-export class CollectionDockingView extends React.Component<SubCollectionViewProps> {
+export class CollectionDockingView extends CollectionSubView(doc => doc) {
     @observable public static Instances: CollectionDockingView[] = [];
     @computed public static get Instance() { return CollectionDockingView.Instances[0]; }
     public static makeDocumentConfig(document: Doc, width?: number, libraryPath?: Doc[]) {
@@ -73,20 +73,13 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
         DragManager.StartWindowDrag = this.StartOtherDrag;
     }
     public StartOtherDrag = (e: any, dragDocs: Doc[]) => {
-        let config: any;
-        if (dragDocs.length === 1) {
-            config = CollectionDockingView.makeDocumentConfig(dragDocs[0]);
-        } else {
-            config = {
+        const config = dragDocs.length === 1 ? CollectionDockingView.makeDocumentConfig(dragDocs[0]) :
+            {
                 type: 'row',
                 content: dragDocs.map((doc, i) => CollectionDockingView.makeDocumentConfig(doc))
             };
-        }
-        const div = document.createElement("div");
-        const dragSource = this._goldenLayout.createDragSource(div, config);
-        dragSource._dragListener.on("dragStop", () => {
-            dragSource.destroy();
-        });
+        const dragSource = this._goldenLayout.createDragSource(document.createElement("div"), config);
+        dragSource._dragListener.on("dragStop", () => dragSource.destroy());
         dragSource._dragListener.onMouseDown(e);
     }
 
@@ -939,8 +932,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
                 backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
                 addDocTab={this.addDocTab}
                 pinToPres={DockedFrameRenderer.PinDoc}
-                docFilters={returnEmptyFilter}
-                searchFilterDocs={returnEmptyDoclist}
+                docFilters={CollectionDockingView.Instance.docFilters}
+                searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
                 fitToBox={true}
             />
             <div className="miniOverlay" onPointerDown={this.miniDown} >
@@ -981,8 +974,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
                 backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
                 addDocTab={this.addDocTab}
                 pinToPres={DockedFrameRenderer.PinDoc}
-                docFilters={returnEmptyFilter}
-                searchFilterDocs={returnEmptyDoclist}
+                docFilters={CollectionDockingView.Instance.docFilters}
+                searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined} />
             {document._viewType === CollectionViewType.Freeform && !this._document?.hideMinimap ? this.renderMiniMap() : (null)}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 5580c32f2..00415dab1 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -180,12 +180,12 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
     };
     _saveFilterCommand = {
         params: ["target"], title: "save filter",
-        script: `self.target._docFilters = copyField(self['target-docFilters']); 
+        script: `self.target._docFilters = compareLists(self['target-docFilters'],self.target._docFilters) ? undefined : copyField(self['target-docFilters']); 
                  self.target._searchFilterDocs = compareLists(self['target-searchFilterDocs'],self.target._searchFilterDocs) ? undefined: copyField(self['target-searchFilterDocs']);`,
         immediate: undoBatch((source: Doc[]) => { this.target._docFilters = undefined; this.target._searchFilterDocs = undefined; }),
         initialize: (button: Doc) => {
-            button['target-docFilters'] = this.target._docFilters instanceof ObjectField ? ObjectField.MakeCopy(this.target._docFilters as any as ObjectField) : undefined;
-            button['target-searchFilterDocs'] = this.target._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(this.target._searchFilterDocs as any as ObjectField) : undefined;
+            button['target-docFilters'] = Cast(Doc.UserDoc()["search-panel"], Doc, null)._docFilters instanceof ObjectField ? ObjectField.MakeCopy(Cast(Doc.UserDoc()["search-panel"], Doc, null)._docFilters as any as ObjectField) : undefined;
+            button['target-searchFilterDocs'] = Cast(Doc.UserDoc()["search-panel"], Doc, null)._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(Cast(Doc.UserDoc()["search-panel"], Doc, null)._searchFilterDocs as any as ObjectField) : undefined;
         },
     };
 
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 2f1f7a90f..e37644f2f 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -3,7 +3,7 @@ import { action, observable, trace, computed, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { CellInfo } from "react-table";
 import "react-table/react-table.css";
-import { emptyFunction, returnFalse, returnZero, returnOne, returnEmptyFilter, Utils, emptyPath } from "../../../Utils";
+import { emptyFunction, returnFalse, returnZero, returnOne, returnEmptyFilter, Utils, emptyPath, returnEmptyDoclist } from "../../../Utils";
 import { Doc, DocListCast, Field, Opt } from "../../../fields/Doc";
 import { Id } from "../../../fields/FieldSymbols";
 import { KeyCodes } from "../../util/KeyCodes";
@@ -199,6 +199,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             rootSelected: returnFalse,
             fieldKey: this.props.rowProps.column.id as string,
             docFilters: returnEmptyFilter,
+            searchFilterDocs: returnEmptyDoclist,
             ContainingCollectionView: this.props.CollectionView,
             ContainingCollectionDoc: this.props.CollectionView && this.props.CollectionView.props.Document,
             isSelected: returnFalse,
@@ -511,7 +512,8 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell {
         addDocTab: this.props.addDocTab,
         pinToPres: this.props.pinToPres,
         ContentScaling: returnOne,
-        docFilters: returnEmptyFilter
+        docFilters: returnEmptyFilter,
+        searchFilterDocs: returnEmptyDoclist,
     };
     @observable private _field = this.prop.Document[this.prop.fieldKey];
     @observable private _doc = FieldValue(Cast(this._field, Doc));
@@ -691,7 +693,8 @@ export class CollectionSchemaImageCell extends CollectionSchemaCell {
             addDocTab: this.props.addDocTab,
             pinToPres: this.props.pinToPres,
             ContentScaling: returnOne,
-            docFilters: returnEmptyFilter
+            docFilters: returnEmptyFilter,
+            searchFilterDocs: returnEmptyDoclist,
         };
 
         let image = true;
@@ -770,7 +773,8 @@ export class CollectionSchemaListCell extends CollectionSchemaCell {
         addDocTab: this.props.addDocTab,
         pinToPres: this.props.pinToPres,
         ContentScaling: returnOne,
-        docFilters: returnEmptyFilter
+        docFilters: returnEmptyFilter,
+        searchFilterDocs: returnEmptyDoclist,
     };
     @observable private _field = this.prop.Document[this.prop.fieldKey];
     @observable private _optionsList = this._field as List<any>;
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index c73159084..71e891045 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -136,6 +136,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
             let docsforFilter: Doc[] = childDocs;
 
             if (searchDocs.length > 0) {
+                searchDocs = [...searchDocs, ...docs.filter(d => d.z)];
                 docsforFilter = [];
                 const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
                 searchDocs = DocUtils.FilterDocs(searchDocs, this.docFilters(), docRangeFilters, viewSpecScript);
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index e1c81aeab..7de0b14ac 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -14,7 +14,6 @@ import { ComputedField } from "../../../fields/ScriptField";
 import { Cast, FieldValue, NumCast, StrCast } from "../../../fields/Types";
 import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero, returnEmptyDoclist } from "../../../Utils";
 import { Docs, DocumentOptions } from "../../documents/Documents";
-import { DocumentType } from "../../documents/DocumentTypes";
 import { CompileScript, Transformer, ts } from "../../util/Scripting";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
@@ -22,11 +21,12 @@ import { COLLECTION_BORDER_WIDTH } from '../../views/globalCssVariables.scss';
 import { ContextMenu } from "../ContextMenu";
 import '../DocumentDecorations.scss';
 import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
-import { CellProps, CollectionSchemaButtons, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDateCell, CollectionSchemaDocCell, CollectionSchemaImageCell, CollectionSchemaListCell, CollectionSchemaNumberCell, CollectionSchemaStringCell } from "./CollectionSchemaCells";
+import { CellProps, CollectionSchemaButtons, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDateCell, CollectionSchemaDocCell, CollectionSchemaImageCell, CollectionSchemaListCell, CollectionSchemaNumberCell, CollectionSchemaStringCell, CollectionSchemaBooleanCell } from "./CollectionSchemaCells";
 import { CollectionSchemaAddColumnHeader, KeysDropdown } from "./CollectionSchemaHeaders";
 import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC";
 import "./CollectionSchemaView.scss";
 import { CollectionView } from "./CollectionView";
+import { DocumentType } from "../../documents/DocumentTypes";
 
 
 enum ColumnType {
@@ -91,7 +91,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
 
     @observable _cellIsEditing: boolean = false;
     @observable _focusedCell: { row: number, col: number } = { row: 0, col: 0 };
-    @observable _openCollections: Array<string> = [];
+    @observable _openCollections: Set<number> = new Set;
 
     @observable _showDoc: Doc | undefined;
     @observable _showDataDoc: any = "";
@@ -136,16 +136,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
 
     @action
     changeSorting = (col: any) => {
-        if (col.desc === undefined) {
-            // no sorting
-            this.props.changeColumnSort(col, true);
-        } else if (col.desc === true) {
-            // descending sort
-            this.props.changeColumnSort(col, false);
-        } else if (col.desc === false) {
-            // ascending sort
-            this.props.changeColumnSort(col, undefined);
-        }
+        this.props.changeColumnSort(col, col.desc === true ? false : col.desc === false ? undefined : true);
     }
 
     @action
@@ -153,7 +144,6 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
 
     @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); }
     @computed get tableColumns(): Column<Doc>[] {
-
         const possibleKeys = this.props.documentKeys.filter(key => this.props.columns.findIndex(existingKey => existingKey.heading.toUpperCase() === key.toUpperCase()) === -1);
         const columns: Column<Doc>[] = [];
         const tableIsFocused = this.props.isFocused(this.props.Document, false);
@@ -161,27 +151,16 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
         const focusedCol = this._focusedCell.col;
         const isEditable = !this.props.headerIsEditing;
 
-        //if (this.childDocs.reduce((found, doc) => found || doc.type === DocumentType.COL, false)) {
-        columns.push(
-            {
-                expander: true,
-                Header: "",
-                width: 60,
-                Expander: (rowInfo) => {
-                    if (rowInfo.original.type === "collection") {
-                        return rowInfo.isExpanded ?
-                            <div className="collectionSchemaView-expander" onClick={() => this.onCloseCollection(rowInfo.original)}><FontAwesomeIcon icon={"caret-down"} size="lg" /></div> :
-                            <div className="collectionSchemaView-expander" onClick={() => this.onExpandCollection(rowInfo.original)}><FontAwesomeIcon icon={"caret-right"} size="lg" /></div>;
-                    } else {
-                        return null;
-                    }
-                }
+        columns.push({
+            expander: true, Header: "", width: 60,
+            Expander: (rowInfo) => {
+                return rowInfo.original.type !== DocumentType.COL ? (null) :
+                    <div className="collectionSchemaView-expander" onClick={action(() => (this._openCollections[rowInfo.isExpanded ? "delete" : "add"])(rowInfo.viewIndex))}>
+                        <FontAwesomeIcon icon={rowInfo.isExpanded ? "caret-down" : "caret-right"} size="lg" />
+                    </div>;
             }
-        );
-        // }
-        this.props.active;
-
-        const cols = this.props.columns.map(col => {
+        });
+        columns.push(...this.props.columns.map(col => {
             const icon: IconProp = this.getColumnType(col) === ColumnType.Number ? "hashtag" : this.getColumnType(col) === ColumnType.String ? "font" :
                 this.getColumnType(col) === ColumnType.Boolean ? "check-square" : this.getColumnType(col) === ColumnType.Doc ? "file" :
                     this.getColumnType(col) === ColumnType.Image ? "image" : this.getColumnType(col) === ColumnType.List ? "list-ul" :
@@ -209,25 +188,13 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                 width={"100%"}
             />;
 
-
-
             const sortIcon = col.desc === undefined ? "caret-right" : col.desc === true ? "caret-down" : "caret-up";
-
-            const header =
-                <div //className="collectionSchemaView-header"
-                    //onClick={e => this.props.openHeader(col, menuContent, e.clientX, e.clientY)}
-                    className="collectionSchemaView-menuOptions-wrapper"
-                    style={{
-                        background: col.color, padding: "2px",
-                        display: "flex", cursor: "default", height: "100%",
-                    }}>
-                    {/* <FontAwesomeIcon onClick={e => this.props.openHeader(col, e.clientX, e.clientY)} icon={icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} /> */}
-                    {keysDropdown}
-                    <div onClick={e => this.changeSorting(col)}
-                        style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit", cursor: "hand" }}>
-                        <FontAwesomeIcon icon={sortIcon} size="lg" />
-                    </div>
-                </div>;
+            const header = <div className="collectionSchemaView-menuOptions-wrapper" style={{ background: col.color, padding: "2px", display: "flex", cursor: "default", height: "100%", }}>
+                {keysDropdown}
+                <div onClick={e => this.changeSorting(col)} style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit", cursor: "hand" }}>
+                    <FontAwesomeIcon icon={sortIcon} size="lg" />
+                </div>
+            </div>;
 
             return {
                 Header: <MovableColumn columnRenderer={header} columnValue={col} allColumns={this.props.columns} reorderColumns={this.props.reorderColumns} ScreenToLocalTransform={this.props.ScreenToLocalTransform} />,
@@ -260,21 +227,20 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                         showDoc: this.showDoc,
                     };
 
-                    const colType = this.getColumnType(col);
-                    if (colType === ColumnType.Number) return <CollectionSchemaNumberCell {...props} />;
-                    if (colType === ColumnType.String) return <CollectionSchemaStringCell {...props} />;
-                    if (colType === ColumnType.Boolean) return <CollectionSchemaCheckboxCell {...props} />;
-                    if (colType === ColumnType.Doc) return <CollectionSchemaDocCell {...props} />;
-                    if (colType === ColumnType.Image) return <CollectionSchemaImageCell {...props} />;
-                    if (colType === ColumnType.List) return <CollectionSchemaListCell {...props} />;
-                    if (colType === ColumnType.Date) return <CollectionSchemaDateCell {...props} />;
-                    return <CollectionSchemaCell {...props} />;
+                    switch (this.getColumnType(col)) {
+                        case ColumnType.Number: return <CollectionSchemaNumberCell {...props} />;
+                        case ColumnType.String: return <CollectionSchemaStringCell {...props} />;
+                        case ColumnType.Boolean: return <CollectionSchemaCheckboxCell {...props} />;
+                        case ColumnType.Doc: return <CollectionSchemaDocCell {...props} />;
+                        case ColumnType.Image: return <CollectionSchemaImageCell {...props} />;
+                        case ColumnType.List: return <CollectionSchemaListCell {...props} />;
+                        case ColumnType.Date: return <CollectionSchemaDateCell {...props} />;
+                        default: return <CollectionSchemaCell {...props} />;
+                    }
                 },
                 minWidth: 200,
             };
-        });
-        columns.push(...cols);
-
+        }));
         columns.push({
             Header: <CollectionSchemaAddColumnHeader createColumn={this.createColumn} />,
             accessor: (doc: Doc) => 0,
@@ -283,8 +249,8 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                 const rowIndex = rowProps.index;
                 const columnIndex = this.props.columns.map(c => c.heading).indexOf(rowProps.column.id!);
                 const isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused;
-                const props: CellProps = {
-                    row: rowIndex,
+                return <CollectionSchemaButtons  {...{
+                    row: rowProps.index,
                     col: columnIndex,
                     rowProps: rowProps,
                     isFocused: isFocused,
@@ -303,9 +269,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                     setComputed: this.setComputed,
                     getField: this.getField,
                     showDoc: this.showDoc,
-                };
-
-                return <CollectionSchemaButtons {...props} />;
+                }} />;
             },
             width: 28,
             resizable: false
@@ -316,12 +280,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
 
     constructor(props: SchemaTableProps) {
         super(props);
-        // convert old schema columns (list of strings) into new schema columns (list of schema header fields)
-        const oldSchemaHeaders = Cast(this.props.Document._schemaHeaders, listSpec("string"), []);
-        if (oldSchemaHeaders?.length && typeof oldSchemaHeaders[0] !== "object") {
-            const newSchemaHeaders = oldSchemaHeaders.map(i => typeof i === "string" ? new SchemaHeaderField(i, "#f1efeb") : i);
-            this.props.Document._schemaHeaders = new List<SchemaHeaderField>(newSchemaHeaders);
-        } else if (this.props.Document._schemaHeaders === undefined) {
+        if (this.props.Document._schemaHeaders === undefined) {
             this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb"), new SchemaHeaderField("author", "#f1efeb"), new SchemaHeaderField("*lastModified", "#f1efeb", ColumnType.Date),
             new SchemaHeaderField("text", "#f1efeb", ColumnType.String), new SchemaHeaderField("type", "#f1efeb"), new SchemaHeaderField("context", "#f1efeb", ColumnType.Doc)]);
         }
@@ -362,19 +321,10 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
         const isFocused = this._focusedCell.row === row && this._focusedCell.col === col && this.props.isFocused(this.props.Document, true);
         // TODO: editing border doesn't work :(
         return {
-            style: {
-                border: !this.props.headerIsEditing && isFocused ? "2px solid rgb(255, 160, 160)" : "1px solid #f1efeb"
-            }
+            style: { border: !this.props.headerIsEditing && isFocused ? "2px solid rgb(255, 160, 160)" : "1px solid #f1efeb" }
         };
     }
 
-    @action
-    onCloseCollection = (collection: Doc): void => {
-        const index = this._openCollections.findIndex(col => col === collection[Id]);
-        if (index > -1) this._openCollections.splice(index, 1);
-    }
-
-    @action onExpandCollection = (collection: Doc) => this._openCollections.push(collection[Id]);
     @action setCellIsEditing = (isEditing: boolean) => this._cellIsEditing = isEditing;
 
     @action
@@ -431,21 +381,13 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
 
     @action
     getColumnType = (column: SchemaHeaderField): ColumnType => {
-        // added functionality to convert old column type stuff to new column type stuff -syip
         if (column.type && column.type !== 0) {
             return column.type;
         }
         if (columnTypes.get(column.heading)) {
-            column.type = columnTypes.get(column.heading)!;
-            return columnTypes.get(column.heading)!;
-        }
-        const typesDoc = FieldValue(Cast(this.props.Document.schemaColumnTypes, Doc));
-        if (!typesDoc) {
-            column.type = ColumnType.Any;
-            return ColumnType.Any;
+            return column.type = columnTypes.get(column.heading)!;
         }
-        column.type = NumCast(typesDoc[column.heading]);
-        return NumCast(typesDoc[column.heading]);
+        return column.type = ColumnType.Any;
     }
 
     @undoBatch
@@ -474,11 +416,9 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     @computed
     get reactTable() {
         const children = this.childDocs;
-        const hasCollectionChild = children.reduce((found, doc) => found || doc.type === "collection", false);
-        const expandedRowsList = this._openCollections.map(col => children.findIndex(doc => doc[Id] === col).toString());
-        const expanded = {};
-        //@ts-ignore
-        expandedRowsList.forEach(row => expanded[row] = true);
+        const hasCollectionChild = children.reduce((found, doc) => found || doc.type === DocumentType.COL, false);
+        const expanded: { [name: string]: any } = {};
+        Array.from(this._openCollections.keys()).map(col => expanded[col.toString()] = true);
         const rerender = [...this.textWrappedRows]; // TODO: get component to rerender on text wrap change without needign to console.log :((((
 
         return <ReactTable
@@ -496,17 +436,14 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
             expanded={expanded}
             resized={this.resized}
             onResizedChange={this.props.onResizedChange}
-            SubComponent={!hasCollectionChild ? undefined : row => (row.original.type !== "collection") ? (null) :
+            SubComponent={!hasCollectionChild ? undefined : row => (row.original.type !== DocumentType.COL) ? (null) :
                 <div className="reactTable-sub"><SchemaTable {...this.props} Document={row.original} dataDoc={undefined} childDocs={undefined} /></div>}
 
         />;
     }
 
     onContextMenu = (e: React.MouseEvent): void => {
-        if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
-            // ContextMenu.Instance.addItem({ description: "Make DB", event: this.makeDB, icon: "table" });
-            ContextMenu.Instance.addItem({ description: "Toggle text wrapping", event: this.toggleTextwrap, icon: "table" });
-        }
+        ContextMenu.Instance.addItem({ description: "Toggle text wrapping", event: this.toggleTextwrap, icon: "table" });
     }
 
     getField = (row: number, col?: number) => {
@@ -588,9 +525,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     }
 
     onOpenClick = () => {
-        if (this._showDoc) {
-            this.props.addDocTab(this._showDoc, "onRight");
-        }
+        this._showDoc && this.props.addDocTab(this._showDoc, "onRight");
     }
 
     getPreviewTransform = (): Transform => {
@@ -606,7 +541,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
             {StrCast(this.props.Document._chromeStatus) !== "disabled" ? <div className="collectionSchemaView-addRow" onClick={() => this.createRow()}>+ new</div>
                 : undefined}
             {!this._showDoc ? (null) :
-                <div className="collectionSchemaView-documentPreview" //onClick={() => { this.onOpenClick(); }}
+                <div className="collectionSchemaView-documentPreview"
                     style={{
                         position: "absolute", width: 150, height: 150,
                         background: "dimGray", display: "block", top: 0, left: 0,
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 4568a6b16..6dd85b7f5 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -1,7 +1,7 @@
 import { action, observable } from 'mobx';
 import { observer } from "mobx-react";
 import { Doc, Field, Opt } from '../../../fields/Doc';
-import { emptyFunction, returnFalse, returnOne, returnZero, returnEmptyFilter } from '../../../Utils';
+import { emptyFunction, returnFalse, returnOne, returnZero, returnEmptyFilter, returnEmptyDoclist } from '../../../Utils';
 import { Docs } from '../../documents/Documents';
 import { Transform } from '../../util/Transform';
 import { undoBatch } from '../../util/UndoManager';
@@ -56,7 +56,8 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             Document: this.props.doc,
             DataDoc: this.props.doc,
             LibraryPath: [],
-            docFilters:returnEmptyFilter,
+            docFilters: returnEmptyFilter,
+            searchFilterDocs: returnEmptyDoclist,
             ContainingCollectionView: undefined,
             ContainingCollectionDoc: undefined,
             fieldKey: this.props.keyName,
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 5250a8f58..ba0ac6293 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -906,7 +906,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             search => {
                 search ? this.highlightSearchTerms([Doc.SearchQuery()], search.searchMatch < 0) : this.unhighlightSearchTerms();
             },
-            { fireImmediately: Doc.IsSearchMatch(this.rootDoc) ? true : false });
+            { fireImmediately: Doc.IsSearchMatchUnmemoized(this.rootDoc) ? true : false });
 
         this._disposers.record = reaction(() => this._recording,
             () => {
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 9c9900bfb..e93fc86b5 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -5,7 +5,7 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, DocListCast, Field, Opt } from '../../../fields/Doc';
 import { documentSchema } from "../../../fields/documentSchemas";
-import { Id } from '../../../fields/FieldSymbols';
+import { Id, Copy } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { createSchema, listSpec, makeInterface } from '../../../fields/Schema';
 import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
@@ -15,12 +15,11 @@ import { Docs } from '../../documents/Documents';
 import { DocumentType } from "../../documents/DocumentTypes";
 import { SetupDrag } from '../../util/DragManager';
 import { SearchUtil } from '../../util/SearchUtil';
-import { SelectionManager } from '../../util/SelectionManager';
 import { Transform } from '../../util/Transform';
+import { CollectionDockingView } from "../collections/CollectionDockingView";
 import { CollectionSchemaView, ColumnType } from "../collections/CollectionSchemaView";
 import { CollectionViewType } from '../collections/CollectionView';
 import { ViewBoxBaseComponent } from "../DocComponent";
-import { DocumentView } from '../nodes/DocumentView';
 import { FieldView, FieldViewProps } from '../nodes/FieldView';
 import "./SearchBox.scss";
 
@@ -48,9 +47,8 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
 
     private docsforfilter: Doc[] | undefined = [];
     private realTotalResults: number = 0;
-    private collectionRef = React.createRef<HTMLSpanElement>();
+    private collectionRef = React.createRef<HTMLDivElement>();
 
-    @observable _currentSelectedCollection: DocumentView | undefined = undefined;
     @observable _icons: string[] = this._allIcons;
     @observable _results: [Doc, string[], string[]][] = [];
     @observable _visibleElements: JSX.Element[] = [];
@@ -64,7 +62,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
     @observable open = false;
     @observable children = 0;
     @observable newsearchstring = "";
-    @computed get filter() { return this._results?.length && (this._currentSelectedCollection?.props.Document._searchFilterDocs || this._currentSelectedCollection?.props.Document._docFilters); }
+    @computed get filter() { return this._results?.length && (this.currentSelectedCollection?.props.Document._searchFilterDocs || this.currentSelectedCollection?.props.Document._docFilters); }
 
     constructor(props: any) {
         super(props);
@@ -77,25 +75,24 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             this._searchbarOpen = true;
         }
         this._disposers.filters = reaction(() => this.props.Document._docFilters,
-            (filters: any) => this.setSearchFilter(this._currentSelectedCollection, this.filter ? undefined : this.docsforfilter));
+            (filters: any) => this.setSearchFilter(this.currentSelectedCollection, !this.filter ? undefined : this.docsforfilter));
     });
 
     componentWillUnmount() {
         Object.values(this._disposers).forEach(disposer => disposer?.());
     }
 
+    @computed get currentSelectedCollection() { return CollectionDockingView.Instance; }
+
     @action.bound
     onChange(e: React.ChangeEvent<HTMLInputElement>) {
         this.layoutDoc._searchString = e.target.value;
         this.newsearchstring = e.target.value;
         if (e.target.value === "") {
             this.docsforfilter = undefined;
-            this.setSearchFilter(this._currentSelectedCollection, undefined);
+            this.setSearchFilter(this.currentSelectedCollection, undefined);
             this.resetSearch(false);
 
-            if (this._currentSelectedCollection !== undefined) {
-                this._currentSelectedCollection = undefined;
-            }
             this.open = false;
             this._results = [];
             this._resultsSet.clear();
@@ -149,9 +146,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                 const mod = "_t:";
                 const newWords: string[] = [];
                 const oldWords = values[0].split(" ");
-                oldWords.forEach((word, i) => {
-                    i === 0 ? newWords.push(key + mod + "\"" + word + "\"") : newWords.push("AND " + key + mod + "\"" + word + "\"");
-                });
+                oldWords.forEach((word, i) => i === 0 ? newWords.push(key + mod + "\"" + word + "\"") : newWords.push("AND " + key + mod + "\"" + word + "\""));
                 query = `(${query}) AND (${newWords.join(" ")})`;
             }
             else {
@@ -159,22 +154,12 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                     const mod = "_t:";
                     const newWords: string[] = [];
                     const oldWords = values[i].split(" ");
-                    oldWords.forEach((word, i) => {
-                        i === 0 ? newWords.push(key + mod + "\"" + word + "\"") : newWords.push("AND " + key + mod + "\"" + word + "\"");
-                    });
+                    oldWords.forEach((word, i) => i === 0 ? newWords.push(key + mod + "\"" + word + "\"") : newWords.push("AND " + key + mod + "\"" + word + "\""));
                     const v = "(" + newWords.join(" ") + ")";
                     if (i === 0) {
-                        query = `(${query}) AND (${v}`;
-                        if (values.length === 1) {
-                            query = query + ")";
-                        }
-                    }
-                    else if (i === values.length - 1) {
-                        query = query + " OR " + v + ")";
-                    }
-                    else {
-                        query = query + " OR " + v;
+                        query = `(${query}) AND (${v}` + (values.length === 1 ? ")" : "");
                     }
+                    else query = query + " OR " + v + (i === values.length - 1 ? ")" : "");
                 }
             }
         }
@@ -194,40 +179,15 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         return finalDocs;
     }
 
-    //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)
-    getCurCollections(): Doc[] {
-        const selectedDocs: DocumentView[] = SelectionManager.SelectedDocuments();
-        const collections: Doc[] = [];
-        selectedDocs.forEach(async element => {
-            const layout: string = StrCast(element.props.Document.layout);
-            //checks if selected view (element) is a collection. if it is, adds to list to search through
-            if (layout.indexOf("Collection") > -1) {
-                //makes sure collections aren't added more than once
-                if (!collections.includes(element.props.Document)) {
-                    collections.push(element.props.Document);
-                }
-            }
-            //makes sure collections aren't added more than once
-            if (element.props.ContainingCollectionDoc && !collections.includes(element.props.ContainingCollectionDoc)) {
-                collections.push(element.props.ContainingCollectionDoc);
-            }
-        });
-
-        return collections;
-    }
-
-
+    @action
     searchCollection(query: string) {
-        const selectedCollection = SelectionManager.SelectedDocuments()[0];
+        const selectedCollection = this.currentSelectedCollection;//SelectionManager.SelectedDocuments()[0];
         query = query.toLowerCase();
 
         if (selectedCollection !== undefined) {
-            this._currentSelectedCollection = selectedCollection;
+            // this._currentSelectedCollection = selectedCollection;
             let docs = DocListCast(selectedCollection.dataDoc[Doc.LayoutFieldKey(selectedCollection.dataDoc)]);
             const found: [Doc, string[], string[]][] = [];
-            const docsforFilter: Doc[] = [];
             let newarray: Doc[] = [];
 
             while (docs.length > 0) {
@@ -239,14 +199,13 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                         Field.toString(d[key] as Field).toLowerCase().includes(query) && hlights.add(key));
                     if (Array.from(hlights.keys()).length > 0) {
                         found.push([d, Array.from(hlights.keys()), []]);
-                        docsforFilter.push(d);
                     }
                 });
                 docs = newarray;
             }
             this._results = found;
-            this.docsforfilter = docsforFilter;
-            this.setSearchFilter(selectedCollection, this.filter && found.length ? docsforFilter : undefined);
+            this.docsforfilter = this._results.map(r => r[0]);
+            this.setSearchFilter(selectedCollection, this.filter && found.length ? this.docsforfilter : undefined);
             this._numTotalResults = found.length;
             this.realTotalResults = found.length;
         }
@@ -285,11 +244,11 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         this._visibleElements = [];
         this._visibleDocuments = [];
 
-        if (query !== "" || this._searchFullDB === "My Stuff") {
+        if (query || this._searchFullDB === "My Stuff") {
             this._endIndex = 12;
             this._maxSearchIndex = 0;
             this._numTotalResults = -1;
-            this._searchFullDB ? await this.getResults(query) : this.searchCollection(query);
+            this._searchFullDB ? await this.searchDatabase(query) : this.searchCollection(query);
             runInAction(() => {
                 this._searchbarOpen = true;
                 this.resultsScrolled();
@@ -307,8 +266,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         const includeDeleted = this._deletedDocsStatus ? "" : " NOT deleted_b:true";
         const typeExpr = this._onlyAliases ? "NOT {!join from=id to=proto_i}type_t:*" : `(type_t:* OR {!join from=id to=proto_i}type_t:*) ${this._blockedTypes.map(type => `NOT ({!join from=id to=proto_i}type_t:${type}) AND NOT type_t:${type}`).join(" AND ")}`;
         // fq: type_t:collection OR {!join from=id to=proto_i}type_t:collection   q:text_t:hello
-        const query = [baseExpr, authorExpr, includeDeleted, typeExpr].filter(q => q).join(" AND ").replace(/AND $/, "");
-        return query;
+        return [baseExpr, authorExpr, includeDeleted, typeExpr].filter(q => q).join(" AND ").replace(/AND $/, "");
     }
 
     @computed get primarySort() {
@@ -324,7 +282,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         return headers.reduce((p: Opt<string>, header: SchemaHeaderField) => p || (header.desc !== undefined && suffixMap(header.type) ? (header.heading + suffixMap(header.type) + (header.desc ? " desc" : " asc")) : undefined), undefined);
     }
 
-    getResults = async (query: string) => {
+    searchDatabase = async (query: string) => {
         this._lockPromise && (await this._lockPromise);
         this._lockPromise = new Promise(async res => {
             while (this._results.length <= this._endIndex && (this._numTotalResults === -1 || this._maxSearchIndex < this._numTotalResults)) {
@@ -368,6 +326,10 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             }
 
             this.resultsScrolled();
+
+            const selectedCollection = this.currentSelectedCollection;//SelectionManager.SelectedDocuments()[0];
+            this.docsforfilter = this._results.map(r => r[0]);
+            this.setSearchFilter(selectedCollection, this.filter ? this.docsforfilter : undefined);
             res();
         });
         return this._lockPromise;
@@ -400,7 +362,8 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                 y += 300;
             }
         }
-        return Docs.Create.SchemaDocument(Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []), DocListCast(this.dataDoc[this.fieldKey]), { _autoHeight: true, _viewType: CollectionViewType.Schema, title: StrCast(this.layoutDoc._searchString) });
+        const headers = Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []).map(h => { const v = h[Copy](); v.color = "#f1efeb"; return v; });
+        return Docs.Create.SchemaDocument(headers, DocListCast(this.dataDoc[this.fieldKey]), { _autoHeight: true, _viewType: CollectionViewType.Schema, title: StrCast(this.layoutDoc._searchString) });
     }
 
     @action.bound
@@ -416,9 +379,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             Doc.UnBrushDoc(result[0]);
             Doc.ClearSearchMatches();
         });
-        if (close) {
-            this._searchbarOpen = false;
-        }
+        close && (this._searchbarOpen = false);
     }
 
     @action.bound
@@ -470,16 +431,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                 }
             }
         }
-        const oldSchemaHeaders = Cast(this.props.Document._schemaHeaders, listSpec("string"), []);
-        if (oldSchemaHeaders?.length && typeof oldSchemaHeaders[0] !== "object") {
-            const newSchemaHeaders = oldSchemaHeaders.map(i => typeof i === "string" ? new SchemaHeaderField(i, "#f1efeb") : i);
-            headers.forEach(header => {
-                if (oldSchemaHeaders.includes(header) === false) {
-                    newSchemaHeaders.push(new SchemaHeaderField(header, "#f1efeb"));
-                }
-            });
-            this.props.Document._schemaHeaders = new List<SchemaHeaderField>(newSchemaHeaders);
-        } else if (this.props.Document._schemaHeaders === undefined) {
+        if (this.props.Document._schemaHeaders === undefined) {
             this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb")]);
         }
         if (this._maxSearchIndex >= this._numTotalResults) {
@@ -488,44 +440,29 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         }
     }
 
-    findCommonElements(arr2: string[]) {
-        const arr1 = ["layout", "data"];
-        return arr1.some(item => arr2.includes(item));
-    }
-
     getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight
     panelHeight = () => this.props.PanelHeight();
-
-    selectElement = (doc: Doc) => {
-        //this.gotoDocument(this.childDocs.indexOf(doc), NumCasst(this.layoutDoc._itemIndex));
-    }
+    selectElement = (doc: Doc) => { /* this.gotoDocument(this.childDocs.indexOf(doc), NumCasst(this.layoutDoc._itemIndex)); */ }
     returnHeight = () => 31 + 31 * 6;
     returnLength = () => Math.min(window.innerWidth, 51 + 205 * Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []).length);
 
     @action
     changeSearchScope = (scope: string) => {
         this.docsforfilter = undefined;
-        this.setSearchFilter(this._currentSelectedCollection, undefined);
+        this.setSearchFilter(this.currentSelectedCollection, undefined);
         this._searchFullDB = scope;
         this.dataDoc[this.fieldKey] = new List<Doc>([]);
         this.submitSearch();
     }
 
     @computed get scopeButtons() {
-        return <div style={{
-            height: 25,
-            paddingLeft: "4px",
-            paddingRight: "4px",
-            border: "1px solid gray",
-            borderRadius: "0.3em",
-            borderBottom: !this.open ? "1px solid" : "none",
-        }}>
+        return <div style={{ height: 25, paddingLeft: "4px", paddingRight: "4px", border: "1px solid gray", borderRadius: "0.3em", borderBottom: !this.open ? "1px solid" : "none", }}>
             <form className="beta" style={{ justifyContent: "space-evenly", display: "flex" }}>
                 <div style={{ display: "contents" }}>
                     <div className="radio" style={{ margin: 0 }}>
                         <label style={{ fontSize: 12, marginTop: 6 }} >
                             <input type="radio" style={{ marginLeft: -16, marginTop: -1 }} checked={!this._searchFullDB} onChange={() => this.changeSearchScope("")} />
-                            Collection
+                            Dashboard
                         </label>
                     </div>
                     <div className="radio" style={{ margin: 0 }}>
@@ -542,7 +479,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         </div>;
     }
 
-    setSearchFilter = (collectionView: DocumentView | undefined, docsForFilter: Doc[] | undefined) => {
+    setSearchFilter = (collectionView: { props: { Document: Doc } }, docsForFilter: Doc[] | undefined) => {
         if (collectionView) {
             const docFilters = Cast(this.props.Document._docFilters, listSpec("string"), null);
             collectionView.props.Document._searchFilterDocs = docsForFilter?.length ? new List<Doc>(docsForFilter) : undefined;
@@ -561,7 +498,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                         <div style={{ display: "flex", alignItems: "center" }}>
                             <div style={{ position: "absolute", left: 10 }}>
                                 <Tooltip title={<div className="dash-tooltip" >drag search results as collection</div>}>
-                                    <div><FontAwesomeIcon onPointerDown={SetupDrag(this.collectionRef, () => StrCast(this.layoutDoc._searchString) ? this.startDragCollection() : undefined)} icon={"search"} size="lg"
+                                    <div ref={this.collectionRef}><FontAwesomeIcon onPointerDown={SetupDrag(this.collectionRef, () => StrCast(this.layoutDoc._searchString) ? this.startDragCollection() : undefined)} icon={"search"} size="lg"
                                         style={{ cursor: "hand", color: "black", padding: 1, position: "relative" }} /></div>
                                 </Tooltip>
                             </div>
@@ -574,7 +511,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                                         <FontAwesomeIcon icon={"filter"} size="lg"
                                             style={{ cursor: "hand", padding: 1, backgroundColor: this.filter ? "white" : "lightgray", color: this.filter ? "black" : "white" }}
                                             onPointerDown={e => { e.stopPropagation(); SetupDrag(this.collectionRef, () => this.layoutDoc._searchString ? this.startDragCollection() : undefined); }}
-                                            onClick={action(() => this.setSearchFilter(this._currentSelectedCollection, this.filter ? undefined : this.docsforfilter))} />
+                                            onClick={action(() => this.setSearchFilter(this.currentSelectedCollection, this.filter ? undefined : this.docsforfilter))} />
                                     </div>
                                 </Tooltip>
                             </div>
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index af2ea73d5..c2b491454 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -915,6 +915,10 @@ export namespace Doc {
                 brushManager.SearchMatchDoc.has(Doc.GetProto(doc)) ? brushManager.SearchMatchDoc.get(Doc.GetProto(doc)) : undefined;
         })(doc);
     }
+    export function IsSearchMatchUnmemoized(doc: Doc) {
+        return brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) :
+            brushManager.SearchMatchDoc.has(Doc.GetProto(doc)) ? brushManager.SearchMatchDoc.get(Doc.GetProto(doc)) : undefined;
+    }
     export function SetSearchMatch(doc: Doc, results: { searchMatch: number }) {
         if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc;
         brushManager.SearchMatchDoc.set(doc, results);
@@ -1276,7 +1280,7 @@ Scripting.addGlobal(function copyDragFactory(dragFactory: Doc) {
         Doc.SetInPlace(ndoc, "title", ndoc.title + " " + NumCast(dragFactory["dragFactory-count"]).toString(), true);
     }
     return ndoc;
-})
+});
 Scripting.addGlobal(function copyField(field: any) { return field instanceof ObjectField ? ObjectField.MakeCopy(field) : field; });
 Scripting.addGlobal(function docList(field: any) { return DocListCast(field); });
 Scripting.addGlobal(function setInPlace(doc: any, field: any, value: any) { return Doc.SetInPlace(doc, field, value, false); });
diff --git a/src/fields/List.ts b/src/fields/List.ts
index 1c2b89b01..3601f282b 100644
--- a/src/fields/List.ts
+++ b/src/fields/List.ts
@@ -334,5 +334,5 @@ Scripting.addGlobal("List", List);
 Scripting.addGlobal(function compareLists(l1: any, l2: any) {
     const L1 = Cast(l1, listSpec("string"), []);
     const L2 = Cast(l2, listSpec("string"), []);
-    return L1 && L2 && L1.length === L2.length && L2.reduce((p, v) => p && L1.includes(v), true);
+    return !L1 && !L2 ? true : L1 && L2 && L1.length === L2.length && L2.reduce((p, v) => p && L1.includes(v), true);
 }, "compare two lists");
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2

