From d99f64efe9e69f2159f1ad8f851b24533a996ba5 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 26 Feb 2024 12:57:48 -0500
Subject: fixed some string types to be enumerations for dropAction.  fixed bug
 in golden layout dragging where a stack's tabs could disappear.

---
 .../views/collections/collectionSchema/CollectionSchemaView.tsx       | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 31b4a2dd4..eee3836d2 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -10,7 +10,7 @@ import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Ty
 import { emptyFunction, returnEmptyDoclist, returnEmptyString, returnFalse, returnIgnore, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils';
 import { Docs, DocumentOptions, DocUtils, FInfo } from '../../../documents/Documents';
 import { DocumentManager } from '../../../util/DocumentManager';
-import { DragManager } from '../../../util/DragManager';
+import { DragManager, dropActionType } from '../../../util/DragManager';
 import { SelectionManager } from '../../../util/SelectionManager';
 import { undoable, undoBatch } from '../../../util/UndoManager';
 import { ContextMenu } from '../../ContextMenu';
@@ -981,7 +981,7 @@ class CollectionSchemaViewDoc extends ObservableReactComponent<CollectionSchemaV
                 styleProvider={this.noOpacityStyleProvider}
                 waitForDoubleClickToClick={returnNever}
                 defaultDoubleClick={returnIgnore}
-                dragAction="move"
+                dragAction={dropActionType.move}
                 onClickScriptDisable="always"
                 focus={this._props.schema.focusDocument}
                 childFilters={this._props.schema.childDocFilters}
-- 
cgit v1.2.3-70-g09d2


From bd9170eaa21a2fbccd0912f50d40cefaf0bbe47f Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 6 Mar 2024 12:28:24 -0500
Subject: cleaned up some dropActionType strings.  fixed stackingview scrolling
 when always active.  fixed schemaView keys dropdown menu to be a popup. 
 cleaned up  display of key Finfo's

---
 src/client/documents/Documents.ts                  |  46 +++----
 src/client/views/DashboardView.tsx                 |   9 +-
 src/client/views/TemplateMenu.tsx                  |   2 +-
 .../views/collections/CollectionStackingView.tsx   |  15 ++-
 src/client/views/collections/CollectionSubView.tsx |   5 +-
 src/client/views/collections/TreeView.tsx          |   6 +-
 .../collectionSchema/CollectionSchemaView.scss     | 149 +++++++++++----------
 .../collectionSchema/CollectionSchemaView.tsx      |  68 ++++++----
 src/client/views/nodes/LinkAnchorBox.tsx           |   4 +-
 .../views/nodes/RecordingBox/RecordingBox.tsx      |   4 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |   4 +-
 11 files changed, 170 insertions(+), 142 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 031560886..c9b5cb915 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -70,14 +70,14 @@ class EmptyBox {
 }
 
 export enum FInfoFieldType {
-    string,
-    boolean,
-    number,
-    Doc,
-    enumeration,
-    date,
-    list,
-    rtf,
+    string = 'string',
+    boolean = 'boolean',
+    number = 'number',
+    Doc = 'Doc',
+    enumeration = 'enum',
+    date = 'date',
+    list = 'list',
+    rtf = 'rich text',
 }
 export class FInfo {
     description: string = '';
@@ -198,20 +198,20 @@ type DATEt = DateInfo | number;
 type DTYPEt = DTypeInfo | string;
 export class DocumentOptions {
     // coordinate and dimensions depending on view
-    x?: NUMt = new NumInfo('x coordinate of document in a freeform view', false);
-    y?: NUMt = new NumInfo('y coordinate of document in a freeform view', false);
+    x?: NUMt = new NumInfo('horizontal coordinate in freeform view', false);
+    y?: NUMt = new NumInfo('vertical coordinate in freeform view', false);
     z?: NUMt = new NumInfo('whether document is in overlay (1) or not (0)', false, false, [1, 0]);
-    overlayX?: NUMt = new NumInfo('x coordinate of document in a overlay view', false);
-    overlayY?: NUMt = new NumInfo('y coordinate of document in a overlay view', false);
-    text?: RTFt = new RtfInfo('rich text of a text doc', true);
+    overlayX?: NUMt = new NumInfo('horizontal coordinate in overlay view', false);
+    overlayY?: NUMt = new NumInfo('vertical coordinate in overlay view', false);
+    text?: RTFt = new RtfInfo('plain or rich text', true);
     _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height", false);
     _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units");
-    latitude?: NUMt = new NumInfo('latitude coordinate for map views', false);
-    longitude?: NUMt = new NumInfo('longitude coordinate for map views', false);
+    latitude?: NUMt = new NumInfo('latitude coordinate', false);
+    longitude?: NUMt = new NumInfo('longitude coordinate', false);
     routeCoordinates?: STRt = new StrInfo("stores a route's/direction's coordinates (stringified version)"); // for a route document, this stores the route's coordinates
-    markerType?: STRt = new StrInfo('Defines the marker type for a pushpin document');
-    markerColor?: STRt = new StrInfo('Defines the marker color for a pushpin document');
-    map?: STRt = new StrInfo('text location of map');
+    markerType?: STRt = new StrInfo('marker type for a pushpin document');
+    markerColor?: STRt = new StrInfo('marker color for a pushpin document');
+    map?: STRt = new StrInfo('map location name');
     map_type?: STRt = new StrInfo('type of map view', false);
     map_zoom?: NUMt = new NumInfo('zoom of a map view', false);
     map_pitch?: NUMt = new NumInfo('pitch of a map view', false);
@@ -221,11 +221,11 @@ export class DocumentOptions {
     date_range?: STRt = new StrInfo('date range for calendar', false);
 
     wikiData?: STRt = new StrInfo('WikiData ID related to map location');
-    description?: STRt = new StrInfo('A description of the document');
-    _timecodeToShow?: NUMt = new NumInfo('the time that a document should be displayed (e.g., when an annotation shows up as a video plays)', false);
-    _timecodeToHide?: NUMt = new NumInfo('the time that a document should be hidden', false);
-    _width?: NUMt = new NumInfo('displayed width of a document');
-    _height?: NUMt = new NumInfo('displayed height of document');
+    description?: STRt = new StrInfo('description of document');
+    _timecodeToShow?: NUMt = new NumInfo('media timecode when document should appear (e.g., when an annotation shows up as a video plays)', false);
+    _timecodeToHide?: NUMt = new NumInfo('media timecode when document should disappear', false);
+    _width?: NUMt = new NumInfo("width of document in container's coordinates");
+    _height?: NUMt = new NumInfo("height of document in container's coordiantes");
     data_nativeWidth?: NUMt = new NumInfo('native width of data field contents (e.g., the pixel width of an image)', false);
     data_nativeHeight?: NUMt = new NumInfo('native height of data field contents (e.g., the pixel height of an image)', false);
     linearBtnWidth?: NUMt = new NumInfo('unexpanded width of a linear menu button (button "width" changes when it expands)', false);
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 472d419fc..439d250de 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -28,6 +28,7 @@ import { Colors } from './global/globalEnums';
 import { MainViewModal } from './MainViewModal';
 import { ButtonType } from './nodes/FontIconBox/FontIconBox';
 import { ObservableReactComponent } from './ObservableReactComponent';
+import { dropActionType } from '../util/DragManager';
 
 enum DashboardGroup {
     MyDashboards,
@@ -403,7 +404,7 @@ export class DashboardView extends ObservableReactComponent<{}> {
             _layout_fitWidth: true,
             _gridGap: 5,
             _forceActive: true,
-            childDragAction: 'embed',
+            childDragAction: dropActionType.embed,
             treeView_TruncateTitleWidth: 150,
             ignoreClick: true,
             contextMenuIcons: new List<string>(['plus']),
@@ -411,7 +412,7 @@ export class DashboardView extends ObservableReactComponent<{}> {
             _lockedPosition: true,
             layout_boxShadow: '0 0',
             childDontRegisterViews: true,
-            dropAction: 'same',
+            dropAction: dropActionType.same,
             isSystem: true,
             layout_explainer: 'All of the calendars that you have created will appear here.',
         };
@@ -450,7 +451,7 @@ export class DashboardView extends ObservableReactComponent<{}> {
             _layout_fitWidth: true,
             _gridGap: 5,
             _forceActive: true,
-            childDragAction: 'embed',
+            childDragAction: dropActionType.embed,
             treeView_TruncateTitleWidth: 150,
             ignoreClick: true,
             layout_headerButton: myTrailsBtn,
@@ -459,7 +460,7 @@ export class DashboardView extends ObservableReactComponent<{}> {
             _lockedPosition: true,
             layout_boxShadow: '0 0',
             childDontRegisterViews: true,
-            dropAction: 'same',
+            dropAction: dropActionType.same,
             isSystem: true,
             layout_explainer: 'All of the trails that you have created will appear here.',
         };
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 5d9abb460..00195f7d7 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -105,7 +105,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
         const addedTypes = DocListCast(Cast(Doc.UserDoc()['template_clickFuncs'], Doc, null)?.data);
         const templateMenu: Array<JSX.Element> = [];
         this.props.templates?.forEach((checked, template) => templateMenu.push(<TemplateToggle key={template} template={template} checked={checked} toggle={this.toggleTemplate} />));
-        templateMenu.push(<OtherToggle key={'default'} name={'Default'} checked={templateName === 'layout'} toggle={this.toggleDefault} />);
+        templateMenu.push(<OtherToggle key="default" name={firstDoc.layout instanceof Doc ? StrCast(firstDoc.layout.title) : 'Default'} checked={templateName === 'layout'} toggle={this.toggleDefault} />);
         addedTypes.concat(noteTypes).map(template => (template.treeView_Checked = this.templateIsUsed(firstDoc, template)));
         this._addedKeys &&
             Array.from(this._addedKeys)
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index dc391631a..ea1caf58f 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -233,10 +233,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
     moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => {
         return this._props.removeDocument?.(doc) && addDocument?.(doc) ? true : false;
     };
-    createRef = (ele: HTMLDivElement | null) => {
-        this._masonryGridRef = ele;
-        this.createDashEventsTarget(ele!); //so the whole grid is the drop target?
-    };
 
     onChildClickHandler = () => this._props.childClickScript || ScriptCast(this.Document.onChildClick);
     @computed get onChildDoubleClickHandler() {
@@ -679,6 +675,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
 
     observer = new _global.ResizeObserver(() => this._props.setHeight?.(this.headerMargin + (this.isStackingView ? Math.max(...this._refList.map(DivHeight)) : this._refList.reduce((p, r) => p + DivHeight(r), 0))));
 
+    onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
+    _oldWheel: any;
     render() {
         TraceMobx();
         const editableViewProps = {
@@ -699,7 +697,14 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 <div className="collectionStackingMasonry-cont">
                     <div
                         className={this.isStackingView ? 'collectionStackingView' : 'collectionMasonryView'}
-                        ref={this.createRef}
+                        ref={ele => {
+                            this._masonryGridRef = ele;
+                            this.createDashEventsTarget(ele); //so the whole grid is the drop target?
+                            this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
+                            this._oldWheel = ele;
+                            // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
+                            ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+                        }}
                         style={{
                             overflowY: this.isContentActive() ? 'auto' : 'hidden',
                             background: this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor),
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index fdbd1cc90..59a695a3d 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -219,12 +219,13 @@ export function CollectionSubView<X>(moreProps?: X) {
                 const targetDocments = DocListCast(this.dataDoc[this._props.fieldKey]);
                 const someMoved = !dropAction && docDragData.draggedDocuments.some(drag => targetDocments.includes(drag));
                 if (someMoved) docDragData.droppedDocuments = docDragData.droppedDocuments.map((drop, i) => (targetDocments.includes(docDragData.draggedDocuments[i]) ? docDragData.draggedDocuments[i] : drop));
-                if ((!dropAction || dropAction === 'inSame' || dropAction === 'same' || dropAction === 'move' || someMoved) && docDragData.moveDocument) {
+                if ((!dropAction || dropAction === dropActionType.inPlace || dropAction === dropActionType.same || dropAction === dropActionType.move || someMoved) && docDragData.moveDocument) {
                     const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d);
                     const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d);
                     if (movedDocs.length) {
                         const canAdd =
-                            (de.embedKey || dropAction || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.Document)) && (dropAction !== 'inSame' || docDragData.draggedDocuments.every(d => d.embedContainer === this.Document));
+                            (de.embedKey || dropAction || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.Document)) &&
+                            (dropAction !== dropActionType.inPlace || docDragData.draggedDocuments.every(d => d.embedContainer === this.Document));
                         const moved = docDragData.moveDocument(movedDocs, this.Document, canAdd ? this.addDocument : returnFalse);
                         added = canAdd || moved ? moved : undefined;
                     } else if (addedDocs.length) {
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 4f2d8b9c0..285a789e6 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -449,10 +449,10 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
 
         const addDoc = inside ? this.localAdd : parentAddDoc;
         const canAdd = !StrCast((inside ? this.Document : this._props.treeViewParent)?.treeView_FreezeChildren).includes('add') || forceAdd;
-        if (canAdd && (dropAction !== 'inSame' || droppedDocuments.every(d => d.embedContainer === this._props.parentTreeView?.Document))) {
-            const move = (!dropAction || canEmbed || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same' || dropAction === 'inSame') && moveDocument;
+        if (canAdd && (dropAction !== dropActionType.inPlace || droppedDocuments.every(d => d.embedContainer === this._props.parentTreeView?.Document))) {
+            const move = (!dropAction || canEmbed || dropAction === dropActionType.proto || dropAction === dropActionType.move || dropAction === dropActionType.same || dropAction === dropActionType.inPlace) && moveDocument;
             this._props.parentTreeView instanceof TreeView && (this._props.parentTreeView.dropping = true);
-            const res = droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false);
+            const res = droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === dropActionType.proto ? addDoc(d) : false) : addDoc(d)) || added, false);
             this._props.parentTreeView instanceof TreeView && (this._props.parentTreeView.dropping = false);
             return res;
         }
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index fed4e89cf..ac0bd2378 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -38,91 +38,97 @@
                 background: yellow;
             }
         }
+    }
 
-        .schema-column-menu,
-        .schema-filter-menu {
-            background: $light-gray;
-            position: absolute;
-            min-width: 200px;
-            max-width: 400px;
-            display: flex;
-            flex-direction: column;
-            align-items: flex-start;
-            z-index: 1;
-
-            .schema-key-search-input {
-                width: calc(100% - 20px);
-                margin: 10px;
-            }
+    .schema-preview-divider {
+        height: 100%;
+        background: black;
+        cursor: ew-resize;
+    }
+}
 
-            .schema-search-result {
-                cursor: pointer;
-                padding: 5px 10px;
-                width: 100%;
+.schema-column-menu,
+.schema-filter-menu {
+    background: $light-gray;
+    position: relative;
+    min-width: 200px;
+    max-width: 400px;
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+    z-index: 1;
 
-                &:hover {
-                    background-color: $medium-gray;
-                }
+    .schema-key-search-input {
+        width: calc(100% - 20px);
+        margin: 10px;
+    }
 
-                .schema-search-result-type,
-                .schema-search-result-desc {
-                    color: $dark-gray;
-                    font-size: $body-text;
-                }
-            }
+    .schema-search-result {
+        cursor: pointer;
+        padding: 5px 10px;
+        width: 100%;
 
-            .schema-key-search,
-            .schema-new-key-options {
-                width: 100%;
-                display: flex;
-                flex-direction: column;
-                align-items: flex-start;
-            }
+        &:hover {
+            background-color: $medium-gray;
+        }
+        .schema-search-result-type {
+            font-family: 'Courier New', Courier, monospace;
+        }
 
-            .schema-new-key-options {
-                margin: 10px;
-                .schema-key-warning {
-                    color: red;
-                    font-weight: normal;
-                    align-self: center;
-                }
-            }
+        .schema-search-result-type,
+        .schema-search-result-desc {
+            color: $dark-gray;
+            font-size: $body-text;
+        }
+        .schema-search-result-desc {
+            font-style: italic;
+        }
+    }
 
-            .schema-key-list {
-                width: 100%;
-                max-height: 300px;
-                overflow-y: auto;
-            }
+    .schema-key-search,
+    .schema-new-key-options {
+        width: 100%;
+        display: flex;
+        flex-direction: column;
+        align-items: flex-start;
+    }
 
-            .schema-key-type-option {
-                margin: 2px 0px;
+    .schema-new-key-options {
+        margin: 10px;
+        .schema-key-warning {
+            color: red;
+            font-weight: normal;
+            align-self: center;
+        }
+    }
 
-                input {
-                    margin-right: 5px;
-                }
-            }
+    .schema-key-list {
+        width: 100%;
+        max-height: 300px;
+        overflow-y: auto;
+    }
 
-            .schema-key-default-val {
-                margin: 5px 0;
-            }
+    .schema-key-type-option {
+        margin: 2px 0px;
 
-            .schema-column-menu-button {
-                cursor: pointer;
-                padding: 2px 5px;
-                background: $medium-blue;
-                border-radius: 9999px;
-                color: $white;
-                width: fit-content;
-                margin: 5px;
-                align-self: center;
-            }
+        input {
+            margin-right: 5px;
         }
     }
 
-    .schema-preview-divider {
-        height: 100%;
-        background: black;
-        cursor: ew-resize;
+    .schema-key-default-val {
+        margin: 5px 0;
+    }
+
+    .schema-column-menu-button {
+        cursor: pointer;
+        padding: 2px 5px;
+        background: $medium-blue;
+        border-radius: 9999px;
+        color: $white;
+        width: fit-content;
+        margin: 5px;
+        align-self: center;
     }
 }
 
@@ -133,6 +139,7 @@
     .row-menu {
         display: flex;
         justify-content: center;
+        cursor: pointer;
     }
 }
 
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index eee3836d2..12f0ad5e9 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,5 +1,5 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, makeObservable, observable, ObservableMap, observe } from 'mobx';
+import { action, computed, makeObservable, observable, ObservableMap, observe, trace } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, DocListCast, Field, NumListCast, Opt, StrListCast } from '../../../../fields/Doc';
@@ -25,6 +25,8 @@ import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
+import { Popup, PopupTrigger, Type } from 'browndash-components';
+import { SettingsManager } from '../../../util/SettingsManager';
 const { default: { SCHEMA_NEW_NODE_HEIGHT } } = require('../../global/globalCssVariables.module.scss'); // prettier-ignore
 
 export enum ColumnType {
@@ -161,7 +163,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                         (change as any).added.forEach((doc: Doc) => // for each document added 
                             Doc.GetAllPrototypes(doc.value as Doc).forEach(proto => // for all of its prototypes (and itself)
                                 Object.keys(proto).forEach(action(key => // check if any of its keys are new, and add them
-                                    !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo(key, key === 'author'))))));
+                                    !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo("-no description-", key === 'author'))))));
                         break;
                     case 'update': //let oldValue = change.oldValue; // fill this in if the entire child list will ever be reassigned with a new list
                 }
@@ -681,6 +683,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                         } else {
                             this.setKey(this._menuValue, this._newFieldDefault);
                         }
+                        this._columnMenuIndex = undefined;
                     })}>
                     done
                 </div>
@@ -688,12 +691,12 @@ export class CollectionSchemaView extends CollectionSubView() {
         );
     }
 
-    onPassiveWheel = (e: WheelEvent) => {
+    onKeysPassiveWheel = (e: WheelEvent) => {
         // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
-        if (!this._oldWheel.scrollTop && e.deltaY <= 0) e.preventDefault();
+        if (!this._oldKeysWheel.scrollTop && e.deltaY <= 0) e.preventDefault();
         e.stopPropagation();
     };
-    _oldWheel: any;
+    _oldKeysWheel: any;
     @computed get keysDropdown() {
         return (
             <div className="schema-key-search">
@@ -708,9 +711,9 @@ export class CollectionSchemaView extends CollectionSubView() {
                 <div
                     className="schema-key-list"
                     ref={r => {
-                        this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
-                        this._oldWheel = r;
-                        r?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+                        this._oldKeysWheel?.removeEventListener('wheel', this.onKeysPassiveWheel);
+                        this._oldKeysWheel = r;
+                        r?.addEventListener('wheel', this.onKeysPassiveWheel, { passive: false });
                     }}>
                     {this._menuKeys.map(key => (
                         <div
@@ -721,14 +724,14 @@ export class CollectionSchemaView extends CollectionSubView() {
                             }}>
                             <p>
                                 <span className="schema-search-result-key">
-                                    {key}
-                                    {this.fieldInfos.get(key)!.fieldType ? ', ' : ''}
+                                    <b>{key}</b>
+                                    {this.fieldInfos.get(key)!.fieldType ? ':' : ''}
                                 </span>
                                 <span className="schema-search-result-type" style={{ color: this.fieldInfos.get(key)!.readOnly ? 'red' : 'inherit' }}>
                                     {this.fieldInfos.get(key)!.fieldType}
                                 </span>
+                                <span className="schema-search-result-desc">&nbsp;&nbsp;{this.fieldInfos.get(key)!.description}</span>
                             </p>
-                            <p className="schema-search-result-desc">{this.fieldInfos.get(key)!.description}</p>
                         </div>
                     ))}
                 </div>
@@ -740,16 +743,17 @@ export class CollectionSchemaView extends CollectionSubView() {
         const x = this._columnMenuIndex! == -1 ? 0 : this.displayColumnWidths.reduce((total, curr, index) => total + (index < this._columnMenuIndex! ? curr : 0), CollectionSchemaView._rowMenuWidth);
         return (
             <div className="schema-column-menu" style={{ left: x, minWidth: CollectionSchemaView._minColWidth }}>
-                <input className="schema-key-search-input" type="text" value={this._menuValue} onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
+                <input className="schema-key-search-input" type="text" onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
+                {this._makeNewField ? this.newFieldMenu : this.keysDropdown}
+            </div>
+        );
+    }
+    get renderKeysMenu() {
+        console.log('RNDERMENUT:' + this._columnMenuIndex);
+        return (
+            <div className="schema-column-menu" style={{ left: 0, minWidth: CollectionSchemaView._minColWidth }}>
+                <input className="schema-key-search-input" type="text" onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
                 {this._makeNewField ? this.newFieldMenu : this.keysDropdown}
-                <div
-                    className="schema-column-menu-button"
-                    onPointerDown={action(e => {
-                        e.stopPropagation();
-                        this.closeColumnMenu();
-                    })}>
-                    cancel
-                </div>
             </div>
         );
     }
@@ -833,6 +837,8 @@ export class CollectionSchemaView extends CollectionSubView() {
     isContentActive = () => this._props.isSelected() || this._props.isContentActive();
     screenToLocal = () => this.ScreenToLocalBoxXf().translate(-this.tableWidth, 0);
     previewWidthFunc = () => this.previewWidth;
+    onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
+    _oldWheel: any;
     render() {
         return (
             <div className="collectionSchemaView" ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)} onDrop={this.onExternalDrop.bind(this)}>
@@ -841,15 +847,23 @@ export class CollectionSchemaView extends CollectionSubView() {
                     className="schema-table"
                     style={{ width: `calc(100% - ${this.previewWidth}px)` }}
                     onWheel={e => this._props.isContentActive() && e.stopPropagation()}
-                    ref={r => {
-                        // prevent wheel events from passively propagating up through containers
-                        r?.addEventListener('wheel', (e: WheelEvent) => {}, { passive: false });
+                    ref={ele => {
+                        // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
+                        this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
+                        (this._oldWheel = ele)?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
                     }}>
                     <div className="schema-header-row" style={{ height: this.rowHeightFunc() }}>
                         <div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}>
-                            <div className="schema-header-button" onPointerDown={e => (this._columnMenuIndex === -1 ? this.closeColumnMenu() : this.openColumnMenu(-1, true))}>
-                                <FontAwesomeIcon icon="plus" />
-                            </div>
+                            <Popup
+                                placement="right"
+                                background={SettingsManager.userBackgroundColor}
+                                color={SettingsManager.userColor}
+                                toggle={<FontAwesomeIcon onPointerDown={e => this.openColumnMenu(-1, true)} icon="plus" />}
+                                trigger={PopupTrigger.CLICK}
+                                type={Type.TERT}
+                                isOpen={this._columnMenuIndex !== -1 ? false : undefined}
+                                popup={this.renderKeysMenu}
+                            />
                         </div>
                         {this.columnKeys.map((key, index) => (
                             <SchemaColumnHeader
@@ -870,7 +884,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                             />
                         ))}
                     </div>
-                    {this._columnMenuIndex !== undefined && this.renderColumnMenu}
+                    {this._columnMenuIndex !== undefined && this._columnMenuIndex !== -1 && this.renderColumnMenu}
                     {this._filterColumnIndex !== undefined && this.renderFilterMenu}
                     <CollectionSchemaViewDocs schema={this} childDocs={this.sortedDocsFunc} rowHeight={this.rowHeightFunc} setRef={(ref: HTMLDivElement | null) => (this._tableContentRef = ref)} />
                     {this.layoutDoc.chromeHidden ? null : (
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index 00e1f04c5..0a4325d8c 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -5,7 +5,7 @@ import { Utils, emptyFunction, setupMoveUpEvents } from '../../../Utils';
 import { Doc } from '../../../fields/Doc';
 import { NumCast, StrCast } from '../../../fields/Types';
 import { TraceMobx } from '../../../fields/util';
-import { DragManager } from '../../util/DragManager';
+import { DragManager, dropActionType } from '../../util/DragManager';
 import { LinkFollower } from '../../util/LinkFollower';
 import { SelectionManager } from '../../util/SelectionManager';
 import { ViewBoxBaseComponent } from '../DocComponent';
@@ -54,7 +54,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
             const separation = Math.sqrt((pt[0] - e.clientX) * (pt[0] - e.clientX) + (pt[1] - e.clientY) * (pt[1] - e.clientY));
             if (separation > 100) {
                 const dragData = new DragManager.DocumentDragData([this.Document]);
-                dragData.dropAction = 'embed';
+                dragData.dropAction = dropActionType.embed;
                 dragData.dropPropertiesToRemove = ['link_anchor_1_x', 'link_anchor_1_y', 'link_anchor_2_x', 'link_anchor_2_y', 'onClick'];
                 DragManager.StartDocumentDrag([this._ref.current!], dragData, pt[0], pt[1]);
                 return true;
diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
index f6d94ce05..e38a42b29 100644
--- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
@@ -11,7 +11,7 @@ import { Upload } from '../../../../server/SharedMediaTypes';
 import { DocumentType } from '../../../documents/DocumentTypes';
 import { Docs } from '../../../documents/Documents';
 import { DocumentManager } from '../../../util/DocumentManager';
-import { DragManager } from '../../../util/DragManager';
+import { DragManager, dropActionType } from '../../../util/DragManager';
 import { ScriptingGlobals } from '../../../util/ScriptingGlobals';
 import { Presentation } from '../../../util/TrackMovements';
 import { undoBatch } from '../../../util/UndoManager';
@@ -251,7 +251,7 @@ ScriptingGlobals.add(function resumeWorkspaceReplaying(value: Doc, _readOnly_: b
 
 ScriptingGlobals.add(function startRecordingDrag(value: { doc: Doc | string; e: React.PointerEvent }) {
     if (DocCast(value.doc)) {
-        DragManager.StartDocumentDrag([value.e.target as HTMLElement], new DragManager.DocumentDragData([DocCast(value.doc)], 'embed'), value.e.clientX, value.e.clientY);
+        DragManager.StartDocumentDrag([value.e.target as HTMLElement], new DragManager.DocumentDragData([DocCast(value.doc)], dropActionType.embed), value.e.clientX, value.e.clientY);
         value.e.preventDefault();
         return true;
     }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 2d5239f06..4a1a51558 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -30,7 +30,7 @@ import { Docs, DocUtils } from '../../../documents/Documents';
 import { CollectionViewType } from '../../../documents/DocumentTypes';
 import { DictationManager } from '../../../util/DictationManager';
 import { DocumentManager } from '../../../util/DocumentManager';
-import { DragManager } from '../../../util/DragManager';
+import { DragManager, dropActionType } from '../../../util/DragManager';
 import { MakeTemplate } from '../../../util/DropConverter';
 import { LinkManager } from '../../../util/LinkManager';
 import { RTFMarkup } from '../../../util/RTFMarkup';
@@ -624,7 +624,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         docId: draggedDoc[Id],
                         float: 'unset',
                     });
-                    if (!['embed', 'copy'].includes((dropAction ?? '') as any)) {
+                    if (![dropActionType.embed, dropActionType.copy].includes(dropAction ?? dropActionType.move)) {
                         added = dragData.removeDocument?.(draggedDoc) ? true : false;
                     } else {
                         added = true;
-- 
cgit v1.2.3-70-g09d2

