From 7934c38ed641f4a10cd008fe415a50aef1240e10 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 3 Apr 2023 17:28:51 -0400
Subject: fixed dragging doc out of schema and removing schema column sort

---
 .../views/collections/collectionSchema/CollectionSchemaView.tsx     | 6 ++----
 1 file changed, 2 insertions(+), 4 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 d47c9762c..967e10434 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -180,7 +180,6 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     addRow = (doc: Doc | Doc[]) => {
         const result: boolean = this.addDocument(doc);
-        this.setSort(this.sortField, this.sortDesc);
         return result;
     };
 
@@ -362,7 +361,6 @@ export class CollectionSchemaView extends CollectionSubView() {
             const pushedAndDraggedDocs = [...pushedDocs, ...draggedDocs];
             const removed = this.childDocs.slice().filter(doc => !pushedAndDraggedDocs.includes(doc));
             this.dataDoc[this.fieldKey ?? 'data'] = new List<Doc>([...removed, ...draggedDocs, ...pushedDocs]);
-            this.setSort(undefined);
             SelectionManager.DeselectAll();
             draggedDocs.forEach(doc => {
                 const draggedView = DocumentManager.Instance.getFirstDocumentView(doc);
@@ -378,7 +376,6 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     onExternalDrop = async (e: React.DragEvent): Promise<void> => {
         super.onExternalDrop(e, {}, undoBatch(action(docus => docus.map((doc: Doc) => this.addDocument(doc)))));
-        this.setSort(undefined);
     };
 
     onDividerDown = (e: React.PointerEvent) => setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, emptyFunction);
@@ -799,7 +796,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         const desc = BoolCast(this.layoutDoc.sortDesc);
         const docs = !field
             ? this.childDocs
-            : this.childDocs.sort((docA, docB) => {
+            : [...this.childDocs].sort((docA, docB) => {
                   const aStr = Field.toString(docA[field] as Field);
                   const bStr = Field.toString(docB[field] as Field);
                   var out = 0;
@@ -943,6 +940,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 hideLinkAnchors={true}
                                 fitWidth={returnTrue}
                                 scriptContext={this}
+                                canEmbedOnDrag={true}
                             />
                         </div>
                     );
-- 
cgit v1.2.3-70-g09d2


From 96de14ba8ee055c3d18540fa54b979c27c2f6f13 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 10 Apr 2023 17:49:25 -0400
Subject: fixed schema table scroll bar css

---
 package-lock.json                                  | 131 ++++++++++++++++-----
 .../collectionSchema/CollectionSchemaView.scss     |   6 +-
 .../collectionSchema/CollectionSchemaView.tsx      |   5 +-
 3 files changed, 109 insertions(+), 33 deletions(-)

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

diff --git a/package-lock.json b/package-lock.json
index a231d474f..db49a5c24 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2456,7 +2456,7 @@
         "@types/strip-bom": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz",
-            "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=",
+            "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==",
             "dev": true
         },
         "@types/strip-json-comments": {
@@ -2807,7 +2807,7 @@
                 "textarea-caret": {
                     "version": "3.0.2",
                     "resolved": "https://registry.npmjs.org/textarea-caret/-/textarea-caret-3.0.2.tgz",
-                    "integrity": "sha512-gRzeti2YS4did7UJnPQ47wrjD+vp+CJIe9zbsu0bJ987d8QVLvLNG9757rqiQTIy4hGIeFauTTJt5Xkn51UkXg=="
+                    "integrity": "sha1-82DEhpmqGr9xhoCkOjGoUGZcLK8="
                 }
             }
         },
@@ -2906,7 +2906,7 @@
         "after": {
             "version": "0.8.2",
             "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
-            "integrity": "sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA=="
+            "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8="
         },
         "agent-base": {
             "version": "6.0.2",
@@ -3803,7 +3803,7 @@
         "backo2": {
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
-            "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA=="
+            "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
         },
         "bail": {
             "version": "2.0.2",
@@ -3873,7 +3873,7 @@
         "base64-arraybuffer": {
             "version": "0.1.4",
             "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz",
-            "integrity": "sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg=="
+            "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI="
         },
         "base64-js": {
             "version": "1.5.1",
@@ -4846,7 +4846,7 @@
         "component-bind": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
-            "integrity": "sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw=="
+            "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E="
         },
         "component-emitter": {
             "version": "1.3.0",
@@ -4856,7 +4856,7 @@
         "component-inherit": {
             "version": "0.0.3",
             "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
-            "integrity": "sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA=="
+            "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM="
         },
         "compress-commons": {
             "version": "2.1.1",
@@ -5563,7 +5563,7 @@
         "custom-event": {
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz",
-            "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg=="
+            "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU="
         },
         "cyclist": {
             "version": "1.0.1",
@@ -5571,10 +5571,52 @@
             "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
             "dev": true
         },
-        "D": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/D/-/D-1.0.0.tgz",
-            "integrity": "sha512-nQvrCBu7K2pSSEtIM0EEF03FVjcczCXInMt3moLNFbjlWx6bZrX72uT6/1uAXDbnzGUAx9gTyDiQ+vrFi663oA=="
+        "d": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+            "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+            "dev": true,
+            "requires": {
+                "es5-ext": "^0.10.50",
+                "type": "^1.0.1"
+            }
+        },
+        "d3": {
+            "version": "7.8.4",
+            "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.4.tgz",
+            "integrity": "sha512-q2WHStdhiBtD8DMmhDPyJmXUxr6VWRngKyiJ5EfXMxPw+tqT6BhNjhJZ4w3BHsNm3QoVfZLY8Orq/qPFczwKRA==",
+            "requires": {
+                "d3-array": "3",
+                "d3-axis": "3",
+                "d3-brush": "3",
+                "d3-chord": "3",
+                "d3-color": "3",
+                "d3-contour": "4",
+                "d3-delaunay": "6",
+                "d3-dispatch": "3",
+                "d3-drag": "3",
+                "d3-dsv": "3",
+                "d3-ease": "3",
+                "d3-fetch": "3",
+                "d3-force": "3",
+                "d3-format": "3",
+                "d3-geo": "3",
+                "d3-hierarchy": "3",
+                "d3-interpolate": "3",
+                "d3-path": "3",
+                "d3-polygon": "3",
+                "d3-quadtree": "3",
+                "d3-random": "3",
+                "d3-scale": "4",
+                "d3-scale-chromatic": "3",
+                "d3-selection": "3",
+                "d3-shape": "3",
+                "d3-time": "3",
+                "d3-time-format": "4",
+                "d3-timer": "3",
+                "d3-transition": "3",
+                "d3-zoom": "3"
+            }
         },
         "d3-array": {
             "version": "3.2.2",
@@ -6634,7 +6676,7 @@
         "dynamic-dedupe": {
             "version": "0.3.0",
             "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz",
-            "integrity": "sha1-BuRMIj9eTpTXjvnbI6ZRXOL5YqE=",
+            "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==",
             "dev": true,
             "requires": {
                 "xtend": "^4.0.0"
@@ -6764,7 +6806,7 @@
                 "ms": {
                     "version": "2.0.0",
                     "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-                    "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+                    "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
                 },
                 "ws": {
                     "version": "7.4.6",
@@ -6948,6 +6990,28 @@
                 "is-symbol": "^1.0.2"
             }
         },
+        "es5-ext": {
+            "version": "0.10.62",
+            "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
+            "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
+            "dev": true,
+            "requires": {
+                "es6-iterator": "^2.0.3",
+                "es6-symbol": "^3.1.3",
+                "next-tick": "^1.1.0"
+            }
+        },
+        "es6-iterator": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+            "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+            "dev": true,
+            "requires": {
+                "d": "1",
+                "es5-ext": "^0.10.35",
+                "es6-symbol": "^3.1.1"
+            }
+        },
         "es6-promise": {
             "version": "3.2.1",
             "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz",
@@ -9272,7 +9336,7 @@
         "fs-extra": {
             "version": "0.26.7",
             "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz",
-            "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=",
+            "integrity": "sha512-waKu+1KumRhYv8D8gMRCKJGAMI9pRnPuEb1mvgYD0f7wBscg+h6bW4FDTmEZhB9VKxvoTtxW+Y7bnIlB7zja6Q==",
             "requires": {
                 "graceful-fs": "^4.1.2",
                 "jsonfile": "^2.1.0",
@@ -9932,14 +9996,14 @@
                 "isarray": {
                     "version": "2.0.1",
                     "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
-                    "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ=="
+                    "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
                 }
             }
         },
         "has-cors": {
             "version": "1.1.0",
             "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
-            "integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA=="
+            "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk="
         },
         "has-flag": {
             "version": "3.0.0",
@@ -10434,7 +10498,7 @@
             "resolved": "https://registry.npmjs.org/image-size-stream/-/image-size-stream-1.1.0.tgz",
             "integrity": "sha1-Ivou2mbG31AQh0bacUkmSy0l+Gs=",
             "requires": {
-                "image-size": "git+https://github.com/netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1",
+                "image-size": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1",
                 "readable-stream": "^1.0.33",
                 "tryit": "^1.0.1"
             },
@@ -10515,7 +10579,7 @@
         "indexof": {
             "version": "0.0.1",
             "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
-            "integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg=="
+            "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
         },
         "inflight": {
             "version": "1.0.6",
@@ -11626,7 +11690,7 @@
         "jsonfile": {
             "version": "2.4.0",
             "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
-            "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
+            "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==",
             "requires": {
                 "graceful-fs": "^4.1.6"
             }
@@ -12049,7 +12113,7 @@
         "lodash.isequal": {
             "version": "4.5.0",
             "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
-            "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
+            "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
         },
         "lodash.isplainobject": {
             "version": "4.0.6",
@@ -12310,7 +12374,7 @@
         "mathquill": {
             "version": "0.10.1-a",
             "resolved": "https://registry.npmjs.org/mathquill/-/mathquill-0.10.1-a.tgz",
-            "integrity": "sha512-snSAEwAtwdwBFSor+nVBnWWQtTw67kgAgKMyAIxuz4ZPboy0qkWZmd7BL3lfOXp/INihhRlU1PcfaAtDaRhmzA==",
+            "integrity": "sha1-vyylaQEAY6w0vNXVKa3Ag3zVPD8=",
             "requires": {
                 "jquery": "^1.12.3"
             },
@@ -12318,7 +12382,7 @@
                 "jquery": {
                     "version": "1.12.4",
                     "resolved": "https://registry.npmjs.org/jquery/-/jquery-1.12.4.tgz",
-                    "integrity": "sha512-UEVp7PPK9xXYSk8xqXCJrkXnKZtlgWkd2GsAQbMRFK6S/ePU2JN5G2Zum8hIVjzR3CpdfSqdqAzId/xd4TJHeg=="
+                    "integrity": "sha1-AeHfuikP5z3rp3zurLD5ui/sngw="
                 }
             }
         },
@@ -19101,8 +19165,15 @@
         "react-resizable-rotatable-draggable": {
             "version": "0.2.0",
             "resolved": "https://registry.npmjs.org/react-resizable-rotatable-draggable/-/react-resizable-rotatable-draggable-0.2.0.tgz",
-            "integrity": "sha512-F8TPx3z7/AcmRViySbYV3LpUWXFpHlGAmKmNcYMgPlS+h1eYFazRG3xYS8Z6e48hWY1EcCny/YNrwRNUrap8CQ==",
-            "requires": {}
+            "integrity": "sha512-F8TPx3z7/AcmRViySbYV3LpUWXFpHlGAmKmNcYMgPlS+h1eYFazRG3xYS8Z6e48hWY1EcCny/YNrwRNUrap8CQ=="
+        },
+        "react-resize-detector": {
+            "version": "7.1.2",
+            "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-7.1.2.tgz",
+            "integrity": "sha512-zXnPJ2m8+6oq9Nn8zsep/orts9vQv3elrpA+R8XTcW7DVVUJ9vwDwMXaBtykAYjMnkCIaOoK9vObyR7ZgFNlOw==",
+            "requires": {
+                "lodash": "^4.17.21"
+            }
         },
         "react-reveal": {
             "version": "1.2.2",
@@ -21694,7 +21765,7 @@
         "to-array": {
             "version": "0.1.4",
             "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
-            "integrity": "sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A=="
+            "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA="
         },
         "to-fast-properties": {
             "version": "2.0.0",
@@ -22066,7 +22137,7 @@
                 "strip-bom": {
                     "version": "3.0.0",
                     "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
-                    "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+                    "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
                     "dev": true
                 }
             }
@@ -23287,7 +23358,7 @@
                 "resolve-cwd": {
                     "version": "2.0.0",
                     "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz",
-                    "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=",
+                    "integrity": "sha512-ccu8zQTrzVr954472aUVPLEcB3YpKSYR3cg/3lo1okzobPBM+1INXBbBZlDbnI/hbEocnf8j0QVo43hQKrbchg==",
                     "dev": true,
                     "requires": {
                         "resolve-from": "^3.0.0"
@@ -23296,7 +23367,7 @@
                 "resolve-from": {
                     "version": "3.0.0",
                     "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
-                    "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
+                    "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==",
                     "dev": true
                 },
                 "semver": {
@@ -23848,7 +23919,7 @@
         "yeast": {
             "version": "0.1.2",
             "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
-            "integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg=="
+            "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk="
         },
         "yn": {
             "version": "3.1.1",
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 1ef2fb4ef..6118aef3f 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -9,7 +9,11 @@
     .schema-table {
         background-color: $white;
         cursor: grab;
-        overflow: scroll;
+
+        .schema-table-content {
+            overflow: overlay;
+            scroll-behavior: smooth;
+        }
 
         .schema-column-menu,
         .schema-filter-menu {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 632abd6cf..46ab08dcd 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -45,6 +45,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     public static _minColWidth: number = 25;
     public static _rowMenuWidth: number = 60;
     public static _previewDividerWidth: number = 4;
+    public static _newNodeInputHeight: number = 30;
 
     @computed get _selectedDocs() {
         return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.context), this.props.Document));
@@ -778,7 +779,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                     {this._filterColumnIndex !== undefined && this.renderFilterMenu}
                     <CollectionSchemaViewDocs schema={this} childDocs={this.sortedDocsFunc} />
 
-                    <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} />
+                    <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} height={CollectionSchemaView._newNodeInputHeight} />
                 </div>
                 {this.previewWidth > 0 && <div className="schema-preview-divider" style={{ width: CollectionSchemaView._previewDividerWidth }} onPointerDown={this.onDividerDown}></div>}
                 {this.previewWidth > 0 && (
@@ -833,7 +834,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
     childScreenToLocal = computedFn((index: number) => () => this.props.schema.props.ScreenToLocalTransform().translate(0, -CollectionSchemaView._rowHeight - index * this.rowHeightFunc()));
     render() {
         return (
-            <div className="schema-table-content">
+            <div className="schema-table-content" style={{ height: `calc(100% - ${CollectionSchemaView._newNodeInputHeight + CollectionSchemaView._rowHeight}px)` }}>
                 {this.props.childDocs().docs.map((doc: Doc, index: number) => {
                     const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField ? undefined : this.props.schema.props.DataDoc;
                     return (
-- 
cgit v1.2.3-70-g09d2


From 12e832da09870c1b08020f3feab327b506893175 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Tue, 11 Apr 2023 12:51:13 -0400
Subject: some fixes to schema filtering, wip

---
 .../collectionSchema/CollectionSchemaView.tsx      | 49 ++++++++--------------
 1 file changed, 18 insertions(+), 31 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 46ab08dcd..245e1abc0 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -3,7 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, observable, ObservableMap, untracked } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
-import { Doc, Field, StrListCast } from '../../../../fields/Doc';
+import { Doc, DocListCast, Field, StrListCast } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { listSpec } from '../../../../fields/Schema';
@@ -61,7 +61,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _newFieldType: ColumnType = ColumnType.Number;
     @observable _menuValue: string = '';
     @observable _filterColumnIndex: number | undefined;
-    @observable _filterValue: string = '';
+    @observable _filterSearchValue: string = '';
 
     get documentKeys() {
         const docs = this.childDocs;
@@ -483,24 +483,17 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     openFilterMenu = (index: number) => {
         this._filterColumnIndex = index;
-        this._filterValue = this.getFieldFilters(this.columnKeys[this._filterColumnIndex!]).map(filter => filter.split(':')[1])[0];
+        this._filterSearchValue = '';
     };
 
     @action
-    closeFilterMenu = (setValue: boolean) => {
-        if (setValue) {
-            if (this._filterValue !== '') {
-                Doc.setDocFilter(this.Document, this.columnKeys[this._filterColumnIndex!], this._filterValue, 'check', false, undefined, false);
-            } else {
-                this.removeFieldFilters(this.columnKeys[this._filterColumnIndex!]);
-            }
-        }
+    closeFilterMenu = () => {
         this._filterColumnIndex = undefined;
     };
 
     openContextMenu = (x: number, y: number, index: number) => {
         this.closeColumnMenu();
-        this.closeFilterMenu(false);
+        this.closeFilterMenu();
         ContextMenu.Instance.clearItems();
         ContextMenu.Instance.addItem({
             description: 'Change field',
@@ -533,15 +526,16 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     onFilterKeyDown = (e: React.KeyboardEvent) => {
-        //prettier-ignore
         switch (e.key) {
-            case 'Enter' : this.closeFilterMenu(true); break;
-            case 'Escape': this.closeFilterMenu(false);break;
+            case 'Enter':
+            case 'Escape':
+                this.closeFilterMenu();
+                break;
         }
     };
 
     @action
-    updateFilterSearch = (e: React.ChangeEvent<HTMLInputElement>) => (this._filterValue = e.target.value);
+    updateFilterSearch = (e: React.ChangeEvent<HTMLInputElement>) => (this._filterSearchValue = e.target.value);
 
     @computed get newFieldMenu() {
         return (
@@ -660,21 +654,16 @@ export class CollectionSchemaView extends CollectionSubView() {
     @computed get renderFilterOptions() {
         const keyOptions: string[] = [];
         const columnKey = this.columnKeys[this._filterColumnIndex!];
-        this.childDocs.forEach(doc => {
-            const key = StrCast(doc[columnKey]);
-            if (keyOptions.includes(key) === false && (key.includes(this._filterValue) || !this._filterValue) && key !== '') {
-                keyOptions.push(key);
+        const allDocs = DocListCast(this.dataDoc[this.props.fieldKey]);
+        allDocs.forEach(doc => {
+            const value = StrCast(doc[columnKey]);
+            if (!keyOptions.includes(value) && value !== '' && (this._filterSearchValue === '' || value.includes(this._filterSearchValue))) {
+                keyOptions.push(value);
             }
         });
 
         const filters = StrListCast(this.Document._docFilters);
-        for (let i = 0; i < (filters?.length ?? 0) - 1; i++) {
-            if (filters[i] === columnKey && keyOptions.includes(filters[i].split(':')[1]) === false) {
-                keyOptions.push(filters[i + 1]);
-            }
-        }
-
-        const options = keyOptions.map(key => {
+        return keyOptions.map(key => {
             let bool = false;
             if (filters !== undefined) {
                 const ind = filters.findIndex(filter => filter.split(':')[1] === key);
@@ -700,21 +689,19 @@ export class CollectionSchemaView extends CollectionSubView() {
                 </div>
             );
         });
-
-        return options;
     }
 
     @computed get renderFilterMenu() {
         const x = this.displayColumnWidths.reduce((total, curr, index) => total + (index < this._filterColumnIndex! ? curr : 0), CollectionSchemaView._rowMenuWidth);
         return (
             <div className="schema-filter-menu" style={{ left: x, minWidth: CollectionSchemaView._minColWidth }}>
-                <input className="schema-filter-input" type="text" value={this._filterValue} onKeyDown={this.onFilterKeyDown} onChange={this.updateFilterSearch} onPointerDown={e => e.stopPropagation()} />
+                <input className="schema-filter-input" type="text" value={this._filterSearchValue} onKeyDown={this.onFilterKeyDown} onChange={this.updateFilterSearch} onPointerDown={e => e.stopPropagation()} />
                 {this.renderFilterOptions}
                 <div
                     className="schema-column-menu-button"
                     onPointerDown={action(e => {
                         e.stopPropagation();
-                        this.closeFilterMenu(true);
+                        this.closeFilterMenu();
                     })}>
                     done
                 </div>
-- 
cgit v1.2.3-70-g09d2


From fb9ec75c46bc237bc6c8df24ee998e6de90168a1 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 12 Apr 2023 20:55:14 -0400
Subject: readonly fields and schema key info display

---
 src/client/documents/Documents.ts                  | 51 ++++++++++++----------
 .../collectionSchema/CollectionSchemaView.scss     | 11 ++++-
 .../collectionSchema/CollectionSchemaView.tsx      | 48 +++++++++++++++-----
 .../collections/collectionSchema/SchemaRowBox.tsx  |  1 +
 .../collectionSchema/SchemaTableCell.tsx           |  8 +++-
 5 files changed, 82 insertions(+), 37 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 979b294e0..6b60c1801 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -69,12 +69,14 @@ class EmptyBox {
 }
 export abstract class FInfo {
     description: string = '';
+    readOnly: boolean = false;
     fieldType?: string;
     values?: Field[];
     // format?: string; // format to display values (e.g, decimal places, $, etc)
     // parse?: ScriptField; // parse a value from a string
-    constructor(d: string) {
+    constructor(d: string, readOnly?: boolean) {
         this.description = d;
+        this.readOnly = readOnly ?? false;
     }
 }
 class BoolInfo extends FInfo {
@@ -84,16 +86,16 @@ class BoolInfo extends FInfo {
 class NumInfo extends FInfo {
     fieldType? = 'number';
     values?: number[] = [];
-    constructor(d: string, values?: number[]) {
-        super(d);
+    constructor(d: string, readOnly?: boolean, values?: number[]) {
+        super(d, readOnly);
         this.values = values;
     }
 }
 class StrInfo extends FInfo {
     fieldType? = 'string';
     values?: string[] = [];
-    constructor(d: string, values?: string[]) {
-        super(d);
+    constructor(d: string, readOnly?: boolean, values?: string[]) {
+        super(d, readOnly);
         this.values = values;
     }
 }
@@ -101,21 +103,24 @@ class DocInfo extends FInfo {
     fieldType? = 'Doc';
     values?: Doc[] = [];
     constructor(d: string, values?: Doc[]) {
-        super(d);
+        super(d, true);
         this.values = values;
     }
 }
 class DimInfo extends FInfo {
     fieldType? = 'DimUnit';
     values? = [DimUnit.Pixel, DimUnit.Ratio];
+    readOnly = true;
 }
 class PEInfo extends FInfo {
     fieldType? = 'pointerEvents';
     values? = ['all', 'none'];
+    readOnly = true;
 }
 class DAInfo extends FInfo {
     fieldType? = 'dropActionType';
     values? = ['alias', 'copy', 'move', 'same', 'proto', 'none'];
+    readOnly = true;
 }
 type BOOLt = BoolInfo | boolean;
 type NUMt = NumInfo | number;
@@ -127,12 +132,12 @@ type DROPt = DAInfo | dropActionType;
 export class DocumentOptions {
     x?: NUMt = new NumInfo('x coordinate of document in a freeform view');
     y?: NUMt = new NumInfo('y coordinage of document in a freeform view');
-    z?: NUMt = new NumInfo('whether document is in overlay (1) or not (0)', [1, 0]);
-    system?: BOOLt = new BoolInfo('is this a system created/owned doc');
-    type?: STRt = new StrInfo('type of document', Array.from(Object.keys(DocumentType)));
+    z?: NUMt = new NumInfo('whether document is in overlay (1) or not (0)', false, [1, 0]);
+    system?: BOOLt = new BoolInfo('is this a system created/owned doc', true);
+    type?: STRt = new StrInfo('type of document', true, Array.from(Object.keys(DocumentType)));
     title?: string;
     _dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
-    allowOverlayDrop?: BOOLt = new BoolInfo('can documents be dropped onto this document without using dragging title bar or holding down embed key (ctrl)?');
+    allowOverlayDrop?: BOOLt = new BoolInfo('can documents be dropped onto this document without using dragging title bar or holding down embed key (ctrl)?', true);
     childDropAction?: DROPt = new DAInfo("what should happen to the source document when it's dropped onto a child of a collection ");
     targetDropAction?: DROPt = new DAInfo('what should happen to the source document when ??? ');
     userColor?: STRt = new StrInfo('color associated with a Dash user (seen in header fields of shared documents)');
@@ -146,14 +151,14 @@ export class DocumentOptions {
     _panY?: NUMt = new NumInfo('vertical pan location of a freeform view');
     _width?: NUMt = new NumInfo('displayed width of a document');
     _height?: NUMt = new NumInfo('displayed height of document');
-    _nativeWidth?: NUMt = new NumInfo('native width of document contents (e.g., the pixel width of an image)');
-    _nativeHeight?: NUMt = new NumInfo('native height of document contents (e.g., the pixel height of an image)');
-    _nativeDimModifiable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers');
-    _nativeHeightUnfrozen?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers');
-    _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height");
-    _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units");
-    _fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)');
-    _fitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content');
+    _nativeWidth?: NUMt = new NumInfo('native width of document contents (e.g., the pixel width of an image)', true);
+    _nativeHeight?: NUMt = new NumInfo('native height of document contents (e.g., the pixel height of an image)', true);
+    _nativeDimModifiable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', true);
+    _nativeHeightUnfrozen?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers', true);
+    _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height", true);
+    _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units", true);
+    _fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)', true);
+    _fitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content', true);
     _contentBounds?: List<number>; // the (forced) bounds of the document to display. format is: [left, top, right, bottom]
     _lockedPosition?: boolean; // lock the x,y coordinates of the document so that it can't be dragged
     _lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed
@@ -196,11 +201,11 @@ export class DocumentOptions {
     _timecodeToShow?: number; // the time that a document should be displayed (e.g., when an annotation shows up as a video plays)
     _timecodeToHide?: number; // the time that a document should be hidden
     _timelineLabel?: boolean; // whether the document exists on a timeline
-    '_carousel-caption-xMargin'?: NUMt = new NumInfo('x margin of caption inside of a carouself collection');
-    '_carousel-caption-yMargin'?: NUMt = new NumInfo('y margin of caption inside of a carouself collection');
-    'icon-nativeWidth'?: NUMt = new NumInfo('native width of icon view');
-    'icon-nativeHeight'?: NUMt = new NumInfo('native height of icon view');
-    'dragFactory-count'?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)');
+    '_carousel-caption-xMargin'?: NUMt = new NumInfo('x margin of caption inside of a carouself collection', true);
+    '_carousel-caption-yMargin'?: NUMt = new NumInfo('y margin of caption inside of a carouself collection', true);
+    'icon-nativeWidth'?: NUMt = new NumInfo('native width of icon view', true);
+    'icon-nativeHeight'?: NUMt = new NumInfo('native height of icon view', true);
+    'dragFactory-count'?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true);
     openFactoryLocation?: string; // an OpenWhere value to place the factory created document
     openFactoryAsDelegate?: boolean; //
     lat?: number;
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 6118aef3f..a9434fde3 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -20,6 +20,7 @@
             background: $light-gray;
             position: absolute;
             min-width: 200px;
+            max-width: 400px;
             display: flex;
             flex-direction: column;
             align-items: flex-start;
@@ -30,14 +31,20 @@
                 margin: 10px;
             }
 
-            .schema-key-search-result {
+            .schema-search-result {
                 cursor: pointer;
-                padding: 2px 10px;
+                padding: 5px 10px;
                 width: 100%;
 
                 &:hover {
                     background-color: $medium-gray;
                 }
+
+                .schema-search-result-type,
+                .schema-search-result-desc {
+                    color: $dark-gray;
+                    font-size: $body-text;
+                }
             }
 
             .schema-key-search,
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 245e1abc0..d3992d12c 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -9,7 +9,7 @@ import { List } from '../../../../fields/List';
 import { listSpec } from '../../../../fields/Schema';
 import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
 import { emptyFunction, returnDefault, returnEmptyDoclist, returnEmptyString, returnFalse, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils';
-import { Docs, DocUtils } from '../../../documents/Documents';
+import { Docs, DocumentOptions, DocUtils, FInfo } from '../../../documents/Documents';
 import { DocumentManager } from '../../../util/DocumentManager';
 import { DragManager } from '../../../util/DragManager';
 import { SelectionManager } from '../../../util/SelectionManager';
@@ -40,6 +40,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _closestDropIndex: number = 0;
     private _previewRef: HTMLDivElement | null = null;
     private _makeNewColumn: boolean = false;
+    private _documentOptions: DocumentOptions = new DocumentOptions();
 
     public static _rowHeight: number = 40;
     public static _minColWidth: number = 25;
@@ -54,7 +55,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _colEles: HTMLDivElement[] = [];
     @observable _displayColumnWidths: number[] | undefined;
     @observable _columnMenuIndex: number | undefined;
-    @observable _menuOptions: string[] = [];
+    @observable _menuOptions: [string, { description: string; type: string; readOnly: boolean }][] = [];
     @observable _newFieldWarning: string = '';
     @observable _makeNewField: boolean = false;
     @observable _newFieldDefault: any = 0;
@@ -63,7 +64,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _filterColumnIndex: number | undefined;
     @observable _filterSearchValue: string = '';
 
-    get documentKeys() {
+    get keyInfos() {
         const docs = this.childDocs;
         const keys: { [key: string]: boolean } = {};
         // bcz: ugh.  this is untracked since otherwise a large collection of documents will blast the server for all their fields.
@@ -75,7 +76,22 @@ export class CollectionSchemaView extends CollectionSubView() {
         untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false)))));
 
         // this.columns.forEach(key => (keys[key.heading] = true));
-        return Array.from(Object.keys(keys));
+
+        let computedKeys: { [key: string]: { description: string; type: string; readOnly: boolean } } = {};
+        Object.keys(keys).forEach((key: string) => {
+            computedKeys[key] = { description: '', type: '', readOnly: false };
+        });
+
+        Object.entries(this._documentOptions).forEach((pair: [string, any]) => {
+            const info: FInfo = pair[1];
+            computedKeys[pair[0]] = { description: info.description, type: info.fieldType ?? '', readOnly: info.readOnly };
+        });
+
+        return computedKeys;
+    }
+
+    get documentKeys() {
+        return Object.keys(this.keyInfos);
     }
 
     @computed get previewWidth() {
@@ -441,7 +457,8 @@ export class CollectionSchemaView extends CollectionSubView() {
     onSearchKeyDown = (e: React.KeyboardEvent) => {
         switch (e.key) {
             case 'Enter':
-                this._menuOptions.length > 0 && this._menuValue.length > 0 ? this.setKey(this._menuOptions[0]) : action(() => (this._makeNewField = true))();
+                const menuKeys = Object.keys(this._menuOptions);
+                menuKeys.length > 0 && this._menuValue.length > 0 ? this.setKey(menuKeys[0]) : action(() => (this._makeNewField = true))();
                 break;
             case 'Escape':
                 this.closeColumnMenu();
@@ -470,7 +487,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._makeNewColumn = false;
         this._columnMenuIndex = index;
         this._menuValue = '';
-        this._menuOptions = this.documentKeys;
+        this._menuOptions = Object.entries(this.keyInfos);
         this._makeNewField = false;
         this._newFieldWarning = '';
         this._makeNewField = false;
@@ -516,7 +533,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     updateKeySearch = (e: React.ChangeEvent<HTMLInputElement>) => {
         this._menuValue = e.target.value;
-        this._menuOptions = this.documentKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
+        this._menuOptions = Object.entries(this.keyInfos).filter(value => value[0].toLowerCase().includes(this._menuValue.toLowerCase()));
     };
 
     getFieldFilters = (field: string) => StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field);
@@ -618,14 +635,23 @@ export class CollectionSchemaView extends CollectionSubView() {
                             { passive: false }
                         )
                     }>
-                    {this._menuOptions.map(key => (
+                    {this._menuOptions.map(([key, info]) => (
                         <div
-                            className="schema-key-search-result"
+                            className="schema-search-result"
                             onPointerDown={e => {
                                 e.stopPropagation();
                                 this.setKey(key);
                             }}>
-                            {key}
+                            <p>
+                                <span className="schema-search-result-key">
+                                    {key}
+                                    {info.type ? ', ' : ''}
+                                </span>
+                                <span className="schema-search-result-type" style={{ color: info.readOnly ? 'red' : 'inherit' }}>
+                                    {info.type}
+                                </span>
+                            </p>
+                            <p className="schema-search-result-desc">{info.description}</p>
                         </div>
                     ))}
                 </div>
@@ -825,7 +851,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                 {this.props.childDocs().docs.map((doc: Doc, index: number) => {
                     const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField ? undefined : this.props.schema.props.DataDoc;
                     return (
-                        <div className="schema-row-wrapper" style={{ maxHeight: CollectionSchemaView._rowHeight }}>
+                        <div className="schema-row-wrapper" style={{ height: CollectionSchemaView._rowHeight }}>
                             <DocumentView
                                 key={doc[Id]}
                                 {...this.props.schema.props}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 2defaae00..aa8a61205 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -123,6 +123,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         <SchemaTableCell
                             key={key}
                             Document={this.rootDoc}
+                            schemaView={this.schemaView}
                             fieldKey={key}
                             columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
                             isRowActive={this.props.isContentActive}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 13e45963e..42c9f9d48 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -9,9 +9,11 @@ import { KeyValueBox } from '../../nodes/KeyValueBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
 import { CollectionSchemaView } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
+import { computed } from 'mobx';
 
 export interface SchemaTableCellProps {
     Document: Doc;
+    schemaView: CollectionSchemaView | undefined;
     fieldKey: string;
     columnWidth: number;
     isRowActive: () => boolean | undefined;
@@ -20,6 +22,10 @@ export interface SchemaTableCellProps {
 
 @observer
 export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
+    get readOnly() {
+        return this.props.schemaView?.keyInfos[this.props.fieldKey].readOnly;
+    }
+
     render() {
         const props: FieldViewProps = {
             Document: this.props.Document,
@@ -50,7 +56,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
 
         return (
             <div className="schema-table-cell" style={{ width: this.props.columnWidth }}>
-                <div className="schemacell-edit-wrapper" style={this.props.isRowActive() ? { cursor: 'text', pointerEvents: 'auto' } : { cursor: 'default', pointerEvents: 'none' }}>
+                <div className="schemacell-edit-wrapper" style={this.props.isRowActive() && !this.readOnly ? { cursor: 'text', pointerEvents: 'auto' } : { cursor: 'default', pointerEvents: 'none' }}>
                     <EditableView
                         contents={<FieldView {...props} />}
                         GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
-- 
cgit v1.2.3-70-g09d2


From 8c5e898b89a6634f54a3961ba3693948c7d991d6 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 19 Apr 2023 21:31:59 -0400
Subject: added date fieldinfo, fixed column drag&drop

---
 src/client/documents/Documents.ts                  |  6 ++
 .../collectionSchema/CollectionSchemaView.tsx      | 75 ++++++++++++++++------
 .../collectionSchema/SchemaColumnHeader.tsx        | 19 +++++-
 3 files changed, 80 insertions(+), 20 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 52f8d5717..60acb55e6 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -123,6 +123,10 @@ class DAInfo extends FInfo {
     values? = ['alias', 'copy', 'move', 'same', 'proto', 'none'];
     readOnly = true;
 }
+class DateInfo extends FInfo {
+    fieldType? = 'date';
+    values?: DateField[] = [];
+}
 type BOOLt = BoolInfo | boolean;
 type NUMt = NumInfo | number;
 type STRt = StrInfo | string;
@@ -130,6 +134,7 @@ type DOCt = DocInfo | Doc;
 type DIMt = DimInfo | typeof DimUnit.Pixel | typeof DimUnit.Ratio;
 type PEVt = PEInfo | 'none' | 'all';
 type DROPt = DAInfo | dropActionType;
+type DATEt = DateInfo | number;
 export class DocumentOptions {
     x?: NUMt = new NumInfo('x coordinate of document in a freeform view');
     y?: NUMt = new NumInfo('y coordinage of document in a freeform view');
@@ -137,6 +142,7 @@ export class DocumentOptions {
     system?: BOOLt = new BoolInfo('is this a system created/owned doc', true);
     type?: STRt = new StrInfo('type of document', true, Array.from(Object.keys(DocumentType)));
     title?: string;
+    creationDate?: DATEt = new DateInfo('date the document was created', true);
     _dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
     allowOverlayDrop?: BOOLt = new BoolInfo('can documents be dropped onto this document without using dragging title bar or holding down embed key (ctrl)?', true);
     childDropAction?: DROPt = new DAInfo("what should happen to the source document when it's dropped onto a child of a collection ");
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index d3992d12c..7cb3c6d93 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -24,13 +24,13 @@ import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
+import { Colors } from '../../global/globalEnums';
 
 export enum ColumnType {
     Number,
     String,
     Boolean,
-    Doc,
-    Image,
+    Date,
 }
 
 const defaultColumnKeys: string[] = ['title', 'type', 'author', 'creationDate', 'text'];
@@ -286,18 +286,13 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @undoBatch
     @action
-    swapColumns = (index1: number, index2: number) => {
-        const tempKey = this.columnKeys[index1];
-        const tempWidth = this.storedColumnWidths[index1];
-
-        let currKeys = this.columnKeys;
-        currKeys[index1] = currKeys[index2];
-        currKeys[index2] = tempKey;
+    moveColumn = (fromIndex: number, toIndex: number) => {
+        let currKeys = this.columnKeys.slice();
+        currKeys.splice(toIndex, 0, currKeys.splice(fromIndex, 1)[0]);
         this.layoutDoc.columnKeys = new List<string>(currKeys);
 
-        let currWidths = this.storedColumnWidths;
-        currWidths[index1] = currWidths[index2];
-        currWidths[index2] = tempWidth;
+        let currWidths = this.storedColumnWidths.slice();
+        currWidths.splice(toIndex, 0, currWidths.splice(fromIndex, 1)[0]);
         this.layoutDoc.columnWidths = new List<number>(currWidths);
     };
 
@@ -310,9 +305,44 @@ export class CollectionSchemaView extends CollectionSubView() {
         });
         DragManager.StartColumnDrag(dragEles, dragData, e.x, e.y);
 
+        document.removeEventListener('pointermove', this.highlightDropColumn);
+        document.addEventListener('pointermove', this.highlightDropColumn);
+        let stopHighlight = (e: PointerEvent) => {
+            document.removeEventListener('pointermove', this.highlightDropColumn);
+            document.removeEventListener('pointerup', stopHighlight);
+        };
+        document.addEventListener('pointerup', stopHighlight);
+
         return true;
     };
 
+    @action
+    highlightDropColumn = (e: PointerEvent) => {
+        e.stopPropagation();
+        const mouseX = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0];
+        let index: number | undefined;
+        this.displayColumnWidths.reduce((total, curr, i) => {
+            if (total <= mouseX && total + curr >= mouseX) {
+                if (mouseX <= total + curr / 2) index = i;
+                else index = i + 1;
+            }
+            return total + curr;
+        }, CollectionSchemaView._rowMenuWidth);
+
+        this._colEles.forEach((colRef, i) => {
+            let leftStyle = '';
+            let rightStyle = '';
+            if (i + 1 === index) rightStyle = `solid 2px ${Colors.MEDIUM_BLUE}`;
+            if (i === index && i === 0) leftStyle = `solid 2px ${Colors.MEDIUM_BLUE}`;
+            colRef.style.borderLeft = leftStyle;
+            colRef.style.borderRight = rightStyle;
+            this.childDocs.forEach(doc => {
+                this._rowEles.get(doc).children[1].children[i].style.borderLeft = leftStyle;
+                this._rowEles.get(doc).children[1].children[i].style.borderRight = rightStyle;
+            });
+        });
+    };
+
     @action
     addRowRef = (doc: Doc, ref: HTMLDivElement) => this._rowEles.set(doc, ref);
 
@@ -354,15 +384,25 @@ export class CollectionSchemaView extends CollectionSubView() {
         if (de.complete.columnDragData) {
             e.stopPropagation();
             const mouseX = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y)[0];
-            let i = de.complete.columnDragData.colIndex;
-            this.displayColumnWidths.reduce((total, curr, index) => {
+            let index = de.complete.columnDragData.colIndex;
+            this.displayColumnWidths.reduce((total, curr, i) => {
                 if (total <= mouseX && total + curr >= mouseX) {
-                    i = index;
+                    if (mouseX <= total + curr / 2) index = i;
+                    else index = i + 1;
                 }
                 return total + curr;
             }, CollectionSchemaView._rowMenuWidth);
-            this.swapColumns(de.complete.columnDragData.colIndex, i);
-            e.stopPropagation();
+            this.moveColumn(de.complete.columnDragData.colIndex, index);
+
+            this._colEles.forEach((colRef, i) => {
+                colRef.style.borderLeft = '';
+                colRef.style.borderRight = '';
+                this.childDocs.forEach(doc => {
+                    this._rowEles.get(doc).children[1].children[i].style.borderLeft = '';
+                    this._rowEles.get(doc).children[1].children[i].style.borderRight = '';
+                });
+            });
+
             return true;
         }
         const draggedDocs = de.complete.docDragData?.draggedDocuments;
@@ -791,7 +831,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                     {this._columnMenuIndex !== undefined && this.renderColumnMenu}
                     {this._filterColumnIndex !== undefined && this.renderFilterMenu}
                     <CollectionSchemaViewDocs schema={this} childDocs={this.sortedDocsFunc} />
-
                     <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} height={CollectionSchemaView._newNodeInputHeight} />
                 </div>
                 {this.previewWidth > 0 && <div className="schema-preview-divider" style={{ width: CollectionSchemaView._previewDividerWidth }} onPointerDown={this.onDividerDown}></div>}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index b133347cf..243fe0c61 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -1,10 +1,12 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed } from 'mobx';
+import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
 import { Colors } from '../../global/globalEnums';
 import './CollectionSchemaView.scss';
+import { SnappingManager } from '../../../util/SnappingManager';
+import { DragManager } from '../../../util/DragManager';
 
 export interface SchemaColumnHeaderProps {
     columnKeys: string[];
@@ -22,6 +24,8 @@ export interface SchemaColumnHeaderProps {
 
 @observer
 export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps> {
+    @observable _ref: HTMLDivElement | null = null;
+
     @computed get fieldKey() {
         return this.props.columnKeys[this.props.columnIndex];
     }
@@ -46,7 +50,18 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
 
     render() {
         return (
-            <div className="schema-column-header" style={{ width: this.props.columnWidths[this.props.columnIndex] }} onPointerDown={this.onPointerDown} ref={col => col && this.props.setColRef(this.props.columnIndex, col)}>
+            <div
+                className="schema-column-header"
+                style={{
+                    width: this.props.columnWidths[this.props.columnIndex],
+                }}
+                onPointerDown={this.onPointerDown}
+                ref={col => {
+                    if (col) {
+                        this._ref = col;
+                        this.props.setColRef(this.props.columnIndex, col);
+                    }
+                }}>
                 <div className="schema-column-resizer left" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex)}></div>
                 <div className="schema-column-title">{this.fieldKey}</div>
 
-- 
cgit v1.2.3-70-g09d2


From 79791c294e948bc5e9f5799b12dec138c7d8b371 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Thu, 20 Apr 2023 01:13:07 -0400
Subject: added schema cell types for images and dates

---
 package-lock.json                                  | 201 ++++++++++++---------
 package.json                                       |   4 +-
 src/client/documents/Documents.ts                  |   4 +-
 .../collectionSchema/CollectionSchemaView.tsx      |  44 +++--
 .../collectionSchema/SchemaTableCell.tsx           | 158 ++++++++++++++--
 5 files changed, 289 insertions(+), 122 deletions(-)

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

diff --git a/package-lock.json b/package-lock.json
index 5f81e1f0f..7d2ef9509 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5580,6 +5580,16 @@
             "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
             "dev": true
         },
+        "d": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+            "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+            "dev": true,
+            "requires": {
+                "es5-ext": "^0.10.50",
+                "type": "^1.0.1"
+            }
+        },
         "d3": {
             "version": "7.8.4",
             "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.4.tgz",
@@ -6960,6 +6970,28 @@
                 "is-symbol": "^1.0.2"
             }
         },
+        "es5-ext": {
+            "version": "0.10.62",
+            "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
+            "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
+            "dev": true,
+            "requires": {
+                "es6-iterator": "^2.0.3",
+                "es6-symbol": "^3.1.3",
+                "next-tick": "^1.1.0"
+            }
+        },
+        "es6-iterator": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+            "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+            "dev": true,
+            "requires": {
+                "d": "1",
+                "es5-ext": "^0.10.35",
+                "es6-symbol": "^3.1.1"
+            }
+        },
         "es6-promise": {
             "version": "3.2.1",
             "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz",
@@ -6971,6 +7003,7 @@
             "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
             "dev": true,
             "requires": {
+                "d": "^1.0.1",
                 "ext": "^1.1.2"
             }
         },
@@ -14015,7 +14048,7 @@
             "dependencies": {
                 "@iarna/cli": {
                     "version": "2.1.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/@iarna/cli/-/cli-2.1.0.tgz",
                     "integrity": "sha512-rvVVqDa2g860niRbqs3D5RhL4la3dc1vwk+NlpKPZxKaMSHtE2se6C2x8NeveN+rcjp3/686X+u+09CZ+7lmAQ==",
                     "requires": {
                         "glob": "^7.1.2",
@@ -14118,7 +14151,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -14133,7 +14166,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -14142,12 +14175,12 @@
                 },
                 "asap": {
                     "version": "2.0.6",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
                     "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
                 },
                 "asn1": {
                     "version": "0.2.6",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
                     "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
                     "requires": {
                         "safer-buffer": "~2.1.0"
@@ -14155,7 +14188,7 @@
                 },
                 "assert-plus": {
                     "version": "1.0.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
                     "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="
                 },
                 "asynckit": {
@@ -14165,22 +14198,22 @@
                 },
                 "aws-sign2": {
                     "version": "0.7.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
                     "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA=="
                 },
                 "aws4": {
                     "version": "1.11.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
                     "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
                 },
                 "balanced-match": {
                     "version": "1.0.2",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
                     "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
                 },
                 "bcrypt-pbkdf": {
                     "version": "1.0.2",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
                     "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
                     "requires": {
                         "tweetnacl": "^0.14.3"
@@ -14201,7 +14234,7 @@
                 },
                 "bluebird": {
                     "version": "3.7.2",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
                     "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
                 },
                 "boxen": {
@@ -14249,7 +14282,7 @@
                 },
                 "cacache": {
                     "version": "12.0.4",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz",
                     "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==",
                     "requires": {
                         "bluebird": "^3.5.5",
@@ -14286,7 +14319,7 @@
                 },
                 "caseless": {
                     "version": "0.12.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
                     "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="
                 },
                 "chalk": {
@@ -14430,7 +14463,7 @@
                 },
                 "combined-stream": {
                     "version": "1.0.8",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
                     "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
                     "requires": {
                         "delayed-stream": "~1.0.0"
@@ -14438,7 +14471,7 @@
                 },
                 "concat-map": {
                     "version": "0.0.1",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
                     "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
                 },
                 "concat-stream": {
@@ -14468,7 +14501,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -14483,7 +14516,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -14492,7 +14525,7 @@
                 },
                 "config-chain": {
                     "version": "1.1.13",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
                     "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
                     "requires": {
                         "ini": "^1.3.4",
@@ -14593,7 +14626,7 @@
                 },
                 "dashdash": {
                     "version": "1.14.1",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
                     "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
                     "requires": {
                         "assert-plus": "^1.0.0"
@@ -14626,7 +14659,7 @@
                 },
                 "decode-uri-component": {
                     "version": "0.2.2",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
                     "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ=="
                 },
                 "deep-extend": {
@@ -14672,7 +14705,7 @@
                 },
                 "dezalgo": {
                     "version": "1.0.4",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz",
                     "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
                     "requires": {
                         "asap": "^2.0.0",
@@ -14724,7 +14757,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -14739,7 +14772,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -14748,7 +14781,7 @@
                 },
                 "ecc-jsbn": {
                     "version": "0.1.2",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
                     "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
                     "requires": {
                         "jsbn": "~0.1.0",
@@ -14783,7 +14816,7 @@
                 },
                 "env-paths": {
                     "version": "2.2.1",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
                     "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="
                 },
                 "err-code": {
@@ -14867,7 +14900,7 @@
                 },
                 "extsprintf": {
                     "version": "1.3.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
                     "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g=="
                 },
                 "fast-json-stable-stringify": {
@@ -14877,12 +14910,12 @@
                 },
                 "figgy-pudding": {
                     "version": "3.5.2",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz",
                     "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw=="
                 },
                 "filter-obj": {
                     "version": "1.1.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
                     "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ=="
                 },
                 "find-npm-prefix": {
@@ -14915,7 +14948,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -14930,7 +14963,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -14939,12 +14972,12 @@
                 },
                 "forever-agent": {
                     "version": "0.6.1",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
                     "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw=="
                 },
                 "form-data": {
                     "version": "2.3.3",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
                     "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
                     "requires": {
                         "asynckit": "^0.4.0",
@@ -14977,7 +15010,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -14992,7 +15025,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -15060,7 +15093,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -15075,7 +15108,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -15084,7 +15117,7 @@
                 },
                 "fs.realpath": {
                     "version": "1.0.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
                     "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
                 },
                 "function-bind": {
@@ -15174,7 +15207,7 @@
                 },
                 "getpass": {
                     "version": "0.1.7",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
                     "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
                     "requires": {
                         "assert-plus": "^1.0.0"
@@ -15182,7 +15215,7 @@
                 },
                 "glob": {
                     "version": "7.2.3",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
                     "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
                     "requires": {
                         "fs.realpath": "^1.0.0",
@@ -15195,7 +15228,7 @@
                     "dependencies": {
                         "minimatch": {
                             "version": "3.1.2",
-                            "resolved": false,
+                            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
                             "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
                             "requires": {
                                 "brace-expansion": "^1.1.7"
@@ -15238,12 +15271,12 @@
                 },
                 "graceful-fs": {
                     "version": "4.2.10",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
                     "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
                 },
                 "har-schema": {
                     "version": "2.0.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
                     "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q=="
                 },
                 "har-validator": {
@@ -15322,7 +15355,7 @@
                 },
                 "http-signature": {
                     "version": "1.2.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
                     "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==",
                     "requires": {
                         "assert-plus": "^1.0.0",
@@ -15449,7 +15482,7 @@
                 },
                 "is-cidr": {
                     "version": "3.1.1",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/is-cidr/-/is-cidr-3.1.1.tgz",
                     "integrity": "sha512-Gx+oErgq1j2jAKCR2Kbq0b3wbH0vQKqZ0wOlHxm0o56nq51Cs/DZA8oz9dMDhbHyHEGgJ86eTeVudtgMMOx3Mw==",
                     "requires": {
                         "cidr-regex": "^2.0.10"
@@ -15528,7 +15561,7 @@
                 },
                 "is-typedarray": {
                     "version": "1.0.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
                     "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
                 },
                 "isarray": {
@@ -15543,12 +15576,12 @@
                 },
                 "isstream": {
                     "version": "0.1.2",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
                     "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="
                 },
                 "jsbn": {
                     "version": "0.1.1",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
                     "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
                 },
                 "json-parse-better-errors": {
@@ -15558,7 +15591,7 @@
                 },
                 "json-parse-even-better-errors": {
                     "version": "2.3.1",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
                     "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
                 },
                 "json-schema": {
@@ -15568,7 +15601,7 @@
                 },
                 "json-stringify-safe": {
                     "version": "5.0.1",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
                     "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
                 },
                 "jsonparse": {
@@ -15786,7 +15819,7 @@
                 },
                 "lock-verify": {
                     "version": "2.2.2",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/lock-verify/-/lock-verify-2.2.2.tgz",
                     "integrity": "sha512-2CUNtr1ZSVKJHcYP8uEzafmmuyauCB5zZimj8TvQd/Lflt9kXVZs+8S+EbAzZLaVUDn8CYGmeC3DFGdYfnCzeQ==",
                     "requires": {
                         "@iarna/cli": "^2.1.0",
@@ -15915,7 +15948,7 @@
                 },
                 "meant": {
                     "version": "1.0.3",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/meant/-/meant-1.0.3.tgz",
                     "integrity": "sha512-88ZRGcNxAq4EH38cQ4D85PM57pikCwS8Z99EWHODxN7KBY+UuPiqzRTtZzS8KTXO/ywSWbdjjJST2Hly/EQxLw=="
                 },
                 "mime-db": {
@@ -15933,7 +15966,7 @@
                 },
                 "minimatch": {
                     "version": "3.1.2",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
                     "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
                     "requires": {
                         "brace-expansion": "^1.1.7"
@@ -15982,7 +16015,7 @@
                 },
                 "mkdirp": {
                     "version": "0.5.6",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
                     "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
                     "requires": {
                         "minimist": "^1.2.6"
@@ -16030,7 +16063,7 @@
                 },
                 "node-gyp": {
                     "version": "5.1.1",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.1.tgz",
                     "integrity": "sha512-WH0WKGi+a4i4DUt2mHnvocex/xPLp9pYt5R6M2JdFB7pJ7Z34hveZ4nDTGTiLXCkitA9T8HFZjhinBCiVHYcWw==",
                     "requires": {
                         "env-paths": "^2.2.0",
@@ -16368,7 +16401,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -16383,7 +16416,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -16397,7 +16430,7 @@
                 },
                 "path-is-absolute": {
                     "version": "1.0.1",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
                     "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="
                 },
                 "path-is-inside": {
@@ -16417,7 +16450,7 @@
                 },
                 "performance-now": {
                     "version": "2.1.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
                     "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
                 },
                 "pify": {
@@ -16466,7 +16499,7 @@
                 },
                 "proto-list": {
                     "version": "1.2.4",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
                     "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="
                 },
                 "protoduck": {
@@ -16489,7 +16522,7 @@
                 },
                 "psl": {
                     "version": "1.9.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
                     "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
                 },
                 "pump": {
@@ -16529,12 +16562,12 @@
                 },
                 "qs": {
                     "version": "6.5.3",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
                     "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA=="
                 },
                 "query-string": {
                     "version": "6.14.1",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz",
                     "integrity": "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==",
                     "requires": {
                         "decode-uri-component": "^0.2.0",
@@ -16545,7 +16578,7 @@
                 },
                 "qw": {
                     "version": "1.0.2",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/qw/-/qw-1.0.2.tgz",
                     "integrity": "sha512-1PhZ/iLKwlVNq45dnerTMKFjMof49uqli7/0QsvPNbX5OJ3IZ8msa9lUpvPheVdP+IYYPrf6cOaVil7S35joVA=="
                 },
                 "rc": {
@@ -16591,7 +16624,7 @@
                 },
                 "read-package-json": {
                     "version": "2.1.2",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz",
                     "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==",
                     "requires": {
                         "glob": "^7.1.1",
@@ -16650,7 +16683,7 @@
                 },
                 "request": {
                     "version": "2.88.2",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
                     "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
                     "requires": {
                         "aws-sign2": "~0.7.0",
@@ -16720,7 +16753,7 @@
                 },
                 "safe-buffer": {
                     "version": "5.2.1",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
                     "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
                 },
                 "safer-buffer": {
@@ -16891,7 +16924,7 @@
                 },
                 "sshpk": {
                     "version": "1.17.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
                     "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==",
                     "requires": {
                         "asn1": "~0.2.3",
@@ -16947,7 +16980,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -16962,7 +16995,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -16976,7 +17009,7 @@
                 },
                 "strict-uri-encode": {
                     "version": "2.0.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
                     "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ=="
                 },
                 "string-width": {
@@ -17132,7 +17165,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -17147,7 +17180,7 @@
                             "dependencies": {
                                 "safe-buffer": {
                                     "version": "5.1.2",
-                                    "resolved": false,
+                                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
                                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
                                 }
                             }
@@ -17166,7 +17199,7 @@
                 },
                 "tough-cookie": {
                     "version": "2.5.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
                     "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
                     "requires": {
                         "psl": "^1.1.28",
@@ -17175,7 +17208,7 @@
                     "dependencies": {
                         "punycode": {
                             "version": "2.1.1",
-                            "resolved": false,
+                            "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
                             "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
                         }
                     }
@@ -17190,7 +17223,7 @@
                 },
                 "tweetnacl": {
                     "version": "0.14.5",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
                     "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
                 },
                 "typedarray": {
@@ -17261,7 +17294,7 @@
                 },
                 "uri-js": {
                     "version": "4.4.1",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
                     "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
                     "requires": {
                         "punycode": "^2.1.0"
@@ -17302,7 +17335,7 @@
                 },
                 "uuid": {
                     "version": "3.4.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
                     "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
                 },
                 "validate-npm-package-license": {
@@ -17324,7 +17357,7 @@
                 },
                 "verror": {
                     "version": "1.10.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
                     "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
                     "requires": {
                         "assert-plus": "^1.0.0",
@@ -17832,9 +17865,9 @@
             }
         },
         "openai": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/openai/-/openai-3.1.0.tgz",
-            "integrity": "sha512-v5kKFH5o+8ld+t0arudj833Mgm3GcgBnbyN9946bj6u7bvel4Yg6YFz2A4HLIYDzmMjIo0s6vSG9x73kOwvdCg==",
+            "version": "3.2.1",
+            "resolved": "https://registry.npmjs.org/openai/-/openai-3.2.1.tgz",
+            "integrity": "sha512-762C9BNlJPbjjlWZi4WYK9iM2tAVAv0uUp1UmI34vb0CN5T2mjB/qM6RYBmNKMh/dN9fC+bxqPwWJZUTWW052A==",
             "requires": {
                 "axios": "^0.26.0",
                 "form-data": "^4.0.0"
@@ -22643,6 +22676,12 @@
             "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
             "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
         },
+        "type": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+            "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==",
+            "dev": true
+        },
         "type-check": {
             "version": "0.4.0",
             "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
diff --git a/package.json b/package.json
index c1ff9fe92..70dcc1845 100644
--- a/package.json
+++ b/package.json
@@ -157,6 +157,7 @@
         "@types/three": "^0.126.2",
         "@types/web": "0.0.53",
         "@webscopeio/react-textarea-autocomplete": "^4.9.1",
+        "D": "^1.0.0",
         "adm-zip": "^0.4.16",
         "archiver": "^3.1.1",
         "array-batcher": "^1.2.3",
@@ -189,7 +190,6 @@
         "csv-parser": "^3.0.0",
         "csv-stringify": "^6.3.0",
         "d3": "^7.6.1",
-        "D": "^1.0.0",
         "depcheck": "^0.9.2",
         "equation-editor-react": "github:bobzel/equation-editor-react#useLocally",
         "exif": "^0.6.0",
@@ -246,7 +246,7 @@
         "nodemon": "^1.19.4",
         "normalize.css": "^8.0.1",
         "npm": "^6.14.18",
-        "openai": "^3.1.0",
+        "openai": "^3.2.1",
         "p-limit": "^2.2.0",
         "passport": "^0.4.0",
         "passport-google-oauth20": "^2.0.0",
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index bd878ca8a..c5b6546d7 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -68,10 +68,10 @@ class EmptyBox {
         return '';
     }
 }
-export abstract class FInfo {
+export class FInfo {
     description: string = '';
     readOnly: boolean = false;
-    fieldType?: string;
+    fieldType?: string = '';
     values?: Field[];
     // format?: string; // format to display values (e.g, decimal places, $, etc)
     // parse?: ScriptField; // parse a value from a string
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 39e223c66..1f76c8099 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -31,8 +31,18 @@ export enum ColumnType {
     String,
     Boolean,
     Date,
+    Image,
+    Any,
 }
 
+export const FInfotoColType: { [key: string]: ColumnType } = {
+    string: ColumnType.String,
+    number: ColumnType.Number,
+    boolean: ColumnType.Boolean,
+    date: ColumnType.Date,
+    image: ColumnType.Image,
+};
+
 const defaultColumnKeys: string[] = ['title', 'type', 'author', 'creationDate', 'text'];
 
 @observer
@@ -42,7 +52,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _makeNewColumn: boolean = false;
     private _documentOptions: DocumentOptions = new DocumentOptions();
 
-    public static _rowHeight: number = 40;
+    public static _rowHeight: number = 50;
     public static _minColWidth: number = 25;
     public static _rowMenuWidth: number = 60;
     public static _previewDividerWidth: number = 4;
@@ -55,7 +65,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _colEles: HTMLDivElement[] = [];
     @observable _displayColumnWidths: number[] | undefined;
     @observable _columnMenuIndex: number | undefined;
-    @observable _menuOptions: [string, { description: string; type: string; readOnly: boolean }][] = [];
+    @observable _fieldInfos: [string, FInfo][] = [];
     @observable _newFieldWarning: string = '';
     @observable _makeNewField: boolean = false;
     @observable _newFieldDefault: any = 0;
@@ -64,7 +74,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _filterColumnIndex: number | undefined;
     @observable _filterSearchValue: string = '';
 
-    get keyInfos() {
+    get fieldInfos() {
         const docs = this.childDocs;
         const keys: { [key: string]: boolean } = {};
         // bcz: ugh.  this is untracked since otherwise a large collection of documents will blast the server for all their fields.
@@ -75,23 +85,23 @@ export class CollectionSchemaView extends CollectionSubView() {
         //TODO Types
         untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false)))));
 
-        // this.columns.forEach(key => (keys[key.heading] = true));
+        let computedKeys: { [key: string]: FInfo } = {};
 
-        let computedKeys: { [key: string]: { description: string; type: string; readOnly: boolean } } = {};
-        Object.keys(keys).forEach((key: string) => {
-            computedKeys[key] = { description: '', type: '', readOnly: false };
+        Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => {
+            computedKeys[pair[0]] = pair[1];
         });
 
-        Object.entries(this._documentOptions).forEach((pair: [string, any]) => {
-            const info: FInfo = pair[1];
-            computedKeys[pair[0]] = { description: info.description, type: info.fieldType ?? '', readOnly: info.readOnly };
+        Object.keys(keys).forEach((key: string) => {
+            if (!(key in computedKeys)) {
+                computedKeys[key] = new FInfo('');
+            }
         });
 
         return computedKeys;
     }
 
     get documentKeys() {
-        return Object.keys(this.keyInfos);
+        return Object.keys(this.fieldInfos);
     }
 
     @computed get previewWidth() {
@@ -497,7 +507,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     onSearchKeyDown = (e: React.KeyboardEvent) => {
         switch (e.key) {
             case 'Enter':
-                const menuKeys = Object.keys(this._menuOptions);
+                const menuKeys = Object.keys(this._fieldInfos);
                 menuKeys.length > 0 && this._menuValue.length > 0 ? this.setKey(menuKeys[0]) : action(() => (this._makeNewField = true))();
                 break;
             case 'Escape':
@@ -527,7 +537,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._makeNewColumn = false;
         this._columnMenuIndex = index;
         this._menuValue = '';
-        this._menuOptions = Object.entries(this.keyInfos);
+        this._fieldInfos = Object.entries(this.fieldInfos);
         this._makeNewField = false;
         this._newFieldWarning = '';
         this._makeNewField = false;
@@ -573,7 +583,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     updateKeySearch = (e: React.ChangeEvent<HTMLInputElement>) => {
         this._menuValue = e.target.value;
-        this._menuOptions = Object.entries(this.keyInfos).filter(value => value[0].toLowerCase().includes(this._menuValue.toLowerCase()));
+        this._fieldInfos = Object.entries(this.fieldInfos).filter(value => value[0].toLowerCase().includes(this._menuValue.toLowerCase()));
     };
 
     getFieldFilters = (field: string) => StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field);
@@ -675,7 +685,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                             { passive: false }
                         )
                     }>
-                    {this._menuOptions.map(([key, info]) => (
+                    {this._fieldInfos.map(([key, info]) => (
                         <div
                             className="schema-search-result"
                             onPointerDown={e => {
@@ -685,10 +695,10 @@ export class CollectionSchemaView extends CollectionSubView() {
                             <p>
                                 <span className="schema-search-result-key">
                                     {key}
-                                    {info.type ? ', ' : ''}
+                                    {info.fieldType ? ', ' : ''}
                                 </span>
                                 <span className="schema-search-result-type" style={{ color: info.readOnly ? 'red' : 'inherit' }}>
-                                    {info.type}
+                                    {info.fieldType}
                                 </span>
                             </p>
                             <p className="schema-search-result-desc">{info.description}</p>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index f9319050e..4e31b1e1e 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -1,15 +1,20 @@
 import React = require('react');
 import { observer } from 'mobx-react';
-import { Doc, Field } from '../../../../fields/Doc';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../../Utils';
+import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
+import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../../Utils';
 import { Transform } from '../../../util/Transform';
 import { EditableView } from '../../EditableView';
 import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { KeyValueBox } from '../../nodes/KeyValueBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
-import { CollectionSchemaView } from './CollectionSchemaView';
+import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
-import { computed } from 'mobx';
+import { action, computed, observable } from 'mobx';
+import { extname } from 'path';
+import { Cast, DateCast } from '../../../../fields/Types';
+import { ImageField } from '../../../../fields/URLField';
+import { DateField } from '../../../../fields/DateField';
+import DatePicker from 'react-datepicker';
 
 export interface SchemaTableCellProps {
     Document: Doc;
@@ -23,10 +28,10 @@ export interface SchemaTableCellProps {
 @observer
 export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     get readOnly() {
-        return this.props.schemaView?.keyInfos[this.props.fieldKey].readOnly;
+        return this.props.schemaView?.fieldInfos[this.props.fieldKey]?.readOnly ?? false;
     }
 
-    render() {
+    get defaultCellContent() {
         const props: FieldViewProps = {
             Document: this.props.Document,
             docFilters: returnEmptyFilter,
@@ -53,21 +58,134 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         };
 
         return (
-            <div className="schema-table-cell" style={{ width: this.props.columnWidth }}>
-                <div className="schemacell-edit-wrapper" style={this.props.isRowActive() && !this.readOnly ? { cursor: 'text', pointerEvents: 'auto' } : { cursor: 'default', pointerEvents: 'none' }}>
-                    <EditableView
-                        contents={<FieldView {...props} />}
-                        GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
-                        SetValue={(value: string, shiftDown?: boolean, enterKey?: boolean) => {
-                            if (shiftDown && enterKey) {
-                                this.props.setColumnValues(this.props.fieldKey, value);
-                            }
-                            return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
-                        }}
-                        editing={this.props.isRowActive() ? undefined : false}
-                    />
-                </div>
+            <div className="schemacell-edit-wrapper">
+                <EditableView
+                    contents={<FieldView {...props} />}
+                    GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
+                    SetValue={(value: string, shiftDown?: boolean, enterKey?: boolean) => {
+                        if (shiftDown && enterKey) {
+                            this.props.setColumnValues(this.props.fieldKey, value);
+                        }
+                        return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
+                    }}
+                    editing={this.props.isRowActive() ? undefined : false}
+                />
+            </div>
+        );
+    }
+
+    getCellWithContent(content: any) {
+        return (
+            <div
+                className="schema-table-cell"
+                style={this.props.isRowActive() && !this.readOnly ? { width: this.props.columnWidth, cursor: 'text', pointerEvents: 'auto' } : { width: this.props.columnWidth, cursor: 'default', pointerEvents: 'none' }}>
+                {content}
             </div>
         );
     }
+
+    get getCellType() {
+        const columnTypeStr = this.props.schemaView?.fieldInfos[this.props.fieldKey]?.fieldType;
+        if (columnTypeStr) {
+            if (columnTypeStr in FInfotoColType) {
+                return FInfotoColType[columnTypeStr];
+            }
+
+            return ColumnType.Any;
+        }
+
+        const cellValue = this.props.Document[this.props.fieldKey];
+        if (cellValue instanceof ImageField) return ColumnType.Image;
+        if (cellValue instanceof DateField) return ColumnType.Date;
+
+        return ColumnType.Any;
+    }
+
+    render() {
+        const cellType: ColumnType = this.getCellType;
+        switch (cellType) {
+            case ColumnType.Image:
+                return <SchemaImageCell {...this.props} />;
+            case ColumnType.Date:
+                return <SchemaDateCell {...this.props} />;
+            default:
+                return this.getCellWithContent(this.defaultCellContent);
+        }
+    }
+}
+
+// mj: most of this is adapted from old schema code so I'm not sure what it does tbh
+@observer
+export class SchemaImageCell extends SchemaTableCell {
+    choosePath(url: URL) {
+        if (url.protocol === 'data') return url.href; // if the url ises the data protocol, just return the href
+        if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href); // otherwise, put it through the cors proxy erver
+        if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href; //Why is this here — good question
+
+        const ext = extname(url.href);
+        return url.href.replace(ext, '_o' + ext);
+    }
+
+    get content() {
+        const field = Cast(this.props.Document[this.props.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc
+        const alts = DocListCast(this.props.Document[this.props.fieldKey + '-alternates']); // retrieve alternate documents that may be rendered as alternate images
+        const altpaths = alts
+            .map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url)
+            .filter(url => url)
+            .map(url => this.choosePath(url)); // access the primary layout data of the alternate documents
+        const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths;
+        // If there is a path, follow it; otherwise, follow a link to a default image icon
+        const url = paths.length ? paths : [Utils.CorsProxy('http://www.cs.brown.edu/~bcz/noImage.png')];
+
+        const aspect = Doc.NativeAspect(this.props.Document); // aspect ratio
+        let width = Math.max(75, this.props.columnWidth); // get a with that is no smaller than 75px
+        const height = Math.max(75, width / aspect); // get a height either proportional to that or 75 px
+        width = height * aspect; // increase the width of the image if necessary to maintain proportionality
+
+        return <img src={url[0]} width={paths.length ? width : '20px'} height={paths.length ? height : '20px'} />;
+    }
+
+    render() {
+        return this.getCellWithContent(this.content);
+    }
+}
+
+@observer
+export class SchemaDateCell extends SchemaTableCell {
+    @observable _pickingDate: boolean = false;
+
+    @computed get date(): DateField {
+        // if the cell is a date field, cast then contents to a date. Otherrwwise, make the contents undefined.
+        return DateCast(this.props.Document[this.props.fieldKey]);
+    }
+
+    @action
+    handleChange = (date: any) => {
+        // const script = CompileScript(date.toString(), { requiredType: "Date", addReturn: true, params: { this: Doc.name } });
+        // if (script.compiled) {
+        //     this.applyToDoc(this._document, this.props.row, this.props.col, script.run);
+        // } else {
+        // ^ DateCast is always undefined for some reason, but that is what the field should be set to
+        this.props.Document[this.props.fieldKey] = new DateField(date as Date);
+        //}
+    };
+
+    get content() {
+        return !this._pickingDate ? (
+            <div onPointerDown={action(() => (this._pickingDate = true))}>{this.defaultCellContent}</div>
+        ) : (
+            <DatePicker
+                selected={this.date.date}
+                onSelect={(date: any) => {
+                    this.handleChange(date);
+                    this._pickingDate = false;
+                }}
+                onChange={(date: any) => this.handleChange(date)}
+            />
+        );
+    }
+
+    render() {
+        return this.getCellWithContent(this.content);
+    }
 }
-- 
cgit v1.2.3-70-g09d2


From 09383542d6b7550f78bc8fba70861454825af150 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 26 Apr 2023 17:22:58 -0400
Subject: fixed schema row arrow key movement and scrolling

---
 .../collectionSchema/CollectionSchemaView.tsx      | 45 +++++++++++++++-------
 1 file changed, 31 insertions(+), 14 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 1f76c8099..f1bbc76b4 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -51,6 +51,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _previewRef: HTMLDivElement | null = null;
     private _makeNewColumn: boolean = false;
     private _documentOptions: DocumentOptions = new DocumentOptions();
+    private _tableContentRef: HTMLDivElement | null = null;
 
     public static _rowHeight: number = 50;
     public static _minColWidth: number = 25;
@@ -147,7 +148,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     rowIndex(doc: Doc) {
-        return this.childDocs.indexOf(doc);
+        return this.sortedDocs.docs.indexOf(doc);
     }
 
     componentDidMount() {
@@ -167,28 +168,34 @@ export class CollectionSchemaView extends CollectionSubView() {
                     {
                         const lastDoc = this._selectedDocs.lastElement();
                         const lastIndex = this.rowIndex(lastDoc);
-                        const curDoc = this.childDocs[lastIndex];
+                        const curDoc = this.sortedDocs.docs[lastIndex];
+                        // const curDoc = this.childDocs[lastIndex];
                         if (lastIndex >= 0 && lastIndex < this.childDocs.length - 1) {
                             !e.shiftKey && this.clearSelection();
-                            const newDoc = this.childDocs[lastIndex + 1];
+                            const newDoc = this.sortedDocs.docs[lastIndex + 1];
                             if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc));
                             else this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1);
+                            this.scrollToDoc(newDoc, {});
                         }
                         e.stopPropagation();
+                        e.preventDefault();
                     }
                     break;
                 case 'ArrowUp':
                     {
                         const firstDoc = this._selectedDocs.lastElement();
                         const firstIndex = this.rowIndex(firstDoc);
-                        const curDoc = this.childDocs[firstIndex];
+                        // const curDoc = this.childDocs[firstIndex];
+                        const curDoc = this.sortedDocs.docs[firstIndex];
                         if (firstIndex > 0 && firstIndex < this.childDocs.length) {
                             !e.shiftKey && this.clearSelection();
-                            const newDoc = this.childDocs[firstIndex - 1];
+                            const newDoc = this.sortedDocs.docs[firstIndex - 1];
                             if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc));
                             else this.addDocToSelection(newDoc, e.shiftKey, firstIndex - 1);
+                            this.scrollToDoc(newDoc, {});
                         }
                         e.stopPropagation();
+                        e.preventDefault();
                     }
                     break;
             }
@@ -474,18 +481,21 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     focusDocument = (doc: Doc, options: DocFocusOptions) => {
         Doc.BrushDoc(doc);
+        this.scrollToDoc(doc, options);
+        return undefined;
+    };
 
-        const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]);
+    scrollToDoc = (doc: Doc, options: DocFocusOptions) => {
+        const found = this._tableContentRef && Array.from(this._tableContentRef.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]);
         if (found) {
-            const top = found.getBoundingClientRect().top;
-            const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
-            if (Math.floor(localTop[1]) !== 0) {
-                let focusSpeed = options.zoomTime ?? 500;
-                smoothScroll(focusSpeed, this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc);
+            const rect = found.getBoundingClientRect();
+            const localRect = this.props.ScreenToLocalTransform().transformBounds(rect.left, rect.top, rect.width, rect.height);
+            if (localRect.y < CollectionSchemaView._rowHeight || localRect.y + localRect.height > this.props.PanelHeight()) {
+                let focusSpeed = options.zoomTime ?? 100;
+                smoothScroll(focusSpeed, this._tableContentRef!, localRect.y + this._tableContentRef!.scrollTop - CollectionSchemaView._rowHeight, options.easeFunc);
                 return focusSpeed;
             }
         }
-        return undefined;
     };
 
     @computed get fieldDefaultInput() {
@@ -840,7 +850,13 @@ export class CollectionSchemaView extends CollectionSubView() {
                     </div>
                     {this._columnMenuIndex !== undefined && this.renderColumnMenu}
                     {this._filterColumnIndex !== undefined && this.renderFilterMenu}
-                    <CollectionSchemaViewDocs schema={this} childDocs={this.sortedDocsFunc} />
+                    <CollectionSchemaViewDocs
+                        schema={this}
+                        childDocs={this.sortedDocsFunc}
+                        setRef={(ref: HTMLDivElement | null) => {
+                            this._tableContentRef = ref;
+                        }}
+                    />
                     <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} height={CollectionSchemaView._newNodeInputHeight} />
                 </div>
                 {this.previewWidth > 0 && <div className="schema-preview-divider" style={{ width: CollectionSchemaView._previewDividerWidth }} onPointerDown={this.onDividerDown}></div>}
@@ -884,6 +900,7 @@ export class CollectionSchemaView extends CollectionSubView() {
 
 interface CollectionSchemaViewDocsProps {
     schema: CollectionSchemaView;
+    setRef: (ref: HTMLDivElement | null) => void;
     childDocs: () => { docs: Doc[] };
 }
 
@@ -894,7 +911,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
     childScreenToLocal = computedFn((index: number) => () => this.props.schema.props.ScreenToLocalTransform().translate(0, -CollectionSchemaView._rowHeight - index * this.rowHeightFunc()));
     render() {
         return (
-            <div className="schema-table-content" style={{ height: `calc(100% - ${CollectionSchemaView._newNodeInputHeight + CollectionSchemaView._rowHeight}px)` }}>
+            <div className="schema-table-content" ref={this.props.setRef} style={{ height: `calc(100% - ${CollectionSchemaView._newNodeInputHeight + CollectionSchemaView._rowHeight}px)` }}>
                 {this.props.childDocs().docs.map((doc: Doc, index: number) => {
                     const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField ? undefined : this.props.schema.props.DataDoc;
                     return (
-- 
cgit v1.2.3-70-g09d2


From d58a3350b1d90f701f5cc18a69f51954c88ea30c Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 26 Apr 2023 17:34:01 -0400
Subject: fixed selection with sorted docs

---
 .../collections/collectionSchema/CollectionSchemaView.tsx      | 10 +++++-----
 1 file changed, 5 insertions(+), 5 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 f1bbc76b4..f6dc2a3d7 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -382,17 +382,17 @@ export class CollectionSchemaView extends CollectionSubView() {
     clearSelection = () => SelectionManager.DeselectAll();
 
     selectRows = (rootDoc: Doc, lastSelected: Doc) => {
-        const index = this.childDocs.indexOf(rootDoc);
-        const lastSelectedRow = this.childDocs.indexOf(lastSelected);
+        const index = this.rowIndex(rootDoc);
+        const lastSelectedRow = this.rowIndex(lastSelected);
         const startRow = Math.min(lastSelectedRow, index);
         const endRow = Math.max(lastSelectedRow, index);
         for (let i = startRow; i <= endRow; i++) {
-            const currDoc = this.childDocs[i];
+            const currDoc = this.sortedDocs.docs[i];
             if (!this._selectedDocs.includes(currDoc)) this.addDocToSelection(currDoc, true, i);
         }
     };
 
-    sortedSelectedDocs = () => this.childDocs.filter(doc => this._selectedDocs.includes(doc));
+    sortedSelectedDocs = () => this.sortedDocs.docs.filter(doc => this._selectedDocs.includes(doc));
 
     setDropIndex = (index: number) => (this._closestDropIndex = index);
 
@@ -491,7 +491,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             const rect = found.getBoundingClientRect();
             const localRect = this.props.ScreenToLocalTransform().transformBounds(rect.left, rect.top, rect.width, rect.height);
             if (localRect.y < CollectionSchemaView._rowHeight || localRect.y + localRect.height > this.props.PanelHeight()) {
-                let focusSpeed = options.zoomTime ?? 100;
+                let focusSpeed = options.zoomTime ?? 50;
                 smoothScroll(focusSpeed, this._tableContentRef!, localRect.y + this._tableContentRef!.scrollTop - CollectionSchemaView._rowHeight, options.easeFunc);
                 return focusSpeed;
             }
-- 
cgit v1.2.3-70-g09d2


From bc550e43b6042176cf59f04cbff51e1b21adaa8a Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Thu, 27 Apr 2023 00:41:43 -0400
Subject: trying to get schema keyboard controls working

---
 .../collectionSchema/CollectionSchemaView.tsx      | 43 ++++++++++++--
 .../collections/collectionSchema/SchemaRowBox.tsx  |  1 +
 .../collectionSchema/SchemaTableCell.tsx           | 65 +++++++++++++---------
 3 files changed, 78 insertions(+), 31 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 f6dc2a3d7..92a04f5ec 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -74,6 +74,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _menuValue: string = '';
     @observable _filterColumnIndex: number | undefined;
     @observable _filterSearchValue: string = '';
+    @observable _selectedCell: [Doc, number] | undefined;
 
     get fieldInfos() {
         const docs = this.childDocs;
@@ -174,8 +175,11 @@ export class CollectionSchemaView extends CollectionSubView() {
                             !e.shiftKey && this.clearSelection();
                             const newDoc = this.sortedDocs.docs[lastIndex + 1];
                             if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc));
-                            else this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1);
-                            this.scrollToDoc(newDoc, {});
+                            else {
+                                this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1);
+                                this._selectedCell && (this._selectedCell[0] = newDoc);
+                                this.scrollToDoc(newDoc, {});
+                            }
                         }
                         e.stopPropagation();
                         e.preventDefault();
@@ -191,13 +195,37 @@ export class CollectionSchemaView extends CollectionSubView() {
                             !e.shiftKey && this.clearSelection();
                             const newDoc = this.sortedDocs.docs[firstIndex - 1];
                             if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc));
-                            else this.addDocToSelection(newDoc, e.shiftKey, firstIndex - 1);
-                            this.scrollToDoc(newDoc, {});
+                            else {
+                                this.addDocToSelection(newDoc, e.shiftKey, firstIndex - 1);
+                                this._selectedCell && (this._selectedCell[0] = newDoc);
+                                this.scrollToDoc(newDoc, {});
+                            }
                         }
                         e.stopPropagation();
                         e.preventDefault();
                     }
                     break;
+                case 'ArrowRight':
+                    if (this._selectedCell) {
+                        this._selectedCell[1] = Math.min(this._selectedCell[1] + 1, this.columnKeys.length - 1);
+                    } else if (this._selectedDocs.length > 0) {
+                        this.selectCell(this._selectedDocs[0], 0);
+                    }
+                    break;
+                case 'ArrowLeft':
+                    if (this._selectedCell) {
+                        this._selectedCell[1] = Math.max(this._selectedCell[1] - 1, 0);
+                    } else if (this._selectedDocs.length > 0) {
+                        this.selectCell(this._selectedDocs[0], 0);
+                    }
+                    break;
+                case 'Backspace': {
+                    this.removeDocument(this._selectedDocs);
+                    break;
+                }
+                case 'Escape': {
+                    this._selectedCell = undefined;
+                }
             }
         }
     };
@@ -392,6 +420,11 @@ export class CollectionSchemaView extends CollectionSubView() {
         }
     };
 
+    @action
+    selectCell = (doc: Doc, index: number) => {
+        this._selectedCell = [doc, index];
+    };
+
     sortedSelectedDocs = () => this.sortedDocs.docs.filter(doc => this._selectedDocs.includes(doc));
 
     setDropIndex = (index: number) => (this._closestDropIndex = index);
@@ -428,7 +461,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             const pushedAndDraggedDocs = [...pushedDocs, ...draggedDocs];
             const removed = this.childDocs.slice().filter(doc => !pushedAndDraggedDocs.includes(doc));
             this.dataDoc[this.fieldKey ?? 'data'] = new List<Doc>([...removed, ...draggedDocs, ...pushedDocs]);
-            SelectionManager.DeselectAll();
+            this.clearSelection();
             draggedDocs.forEach(doc => {
                 const draggedView = DocumentManager.Instance.getFirstDocumentView(doc);
                 if (draggedView) DocumentManager.Instance.RemoveView(draggedView);
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 79808d8f8..f5a16cec0 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -123,6 +123,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         <SchemaTableCell
                             key={key}
                             Document={this.rootDoc}
+                            col={index}
                             schemaView={this.schemaView}
                             fieldKey={key}
                             columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 2325339fc..2b61ea261 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -11,13 +11,16 @@ import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSc
 import './CollectionSchemaView.scss';
 import { action, computed, observable } from 'mobx';
 import { extname } from 'path';
-import { Cast, DateCast } from '../../../../fields/Types';
+import { Cast, DateCast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { DateField } from '../../../../fields/DateField';
 import DatePicker from 'react-datepicker';
+import { Colors } from '../../global/globalEnums';
+import { SelectionManager } from '../../../util/SelectionManager';
 
 export interface SchemaTableCellProps {
     Document: Doc;
+    col: number;
     schemaView: CollectionSchemaView | undefined;
     fieldKey: string;
     columnWidth: number;
@@ -27,10 +30,23 @@ export interface SchemaTableCellProps {
 
 @observer
 export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
-    get readOnly() {
+    private _editorRef: EditableView | null = null;
+
+    @computed get readOnly() {
         return this.props.schemaView?.fieldInfos[this.props.fieldKey]?.readOnly ?? false;
     }
 
+    @computed get selected() {
+        const selected: [Doc, number] | undefined = this.props.schemaView?._selectedCell;
+        return this.props.isRowActive() && selected && selected[0] == this.props.Document && selected[1] == this.props.col;
+    }
+
+    componentDidUpdate() {
+        if (!this.selected) {
+            this._editorRef?.setIsFocused(false);
+        }
+    }
+
     get defaultCellContent() {
         const props: FieldViewProps = {
             Document: this.props.Document,
@@ -60,6 +76,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         return (
             <div className="schemacell-edit-wrapper" style={{ cursor: !this.readOnly ? 'text' : 'default', pointerEvents: !this.readOnly && this.props.isRowActive() ? 'all' : 'none' }}>
                 <EditableView
+                    ref={ref => (this._editorRef = ref)}
                     contents={<FieldView {...props} />}
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
                     SetValue={(value: string, shiftDown?: boolean, enterKey?: boolean) => {
@@ -68,20 +85,12 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
                         }
                         return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
                     }}
-                    editing={this.props.isRowActive() ? undefined : false}
+                    editing={this.selected ? undefined : false}
                 />
             </div>
         );
     }
 
-    getCellWithContent(content: any) {
-        return (
-            <div className="schema-table-cell" style={this.props.isRowActive() && !this.readOnly ? { width: this.props.columnWidth } : { width: this.props.columnWidth }}>
-                {content}
-            </div>
-        );
-    }
-
     get getCellType() {
         const columnTypeStr = this.props.schemaView?.fieldInfos[this.props.fieldKey]?.fieldType;
         if (columnTypeStr) {
@@ -99,7 +108,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         return ColumnType.Any;
     }
 
-    render() {
+    get content() {
         const cellType: ColumnType = this.getCellType;
         switch (cellType) {
             case ColumnType.Image:
@@ -107,14 +116,27 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             case ColumnType.Date:
             // return <SchemaDateCell {...this.props} />;
             default:
-                return this.getCellWithContent(this.defaultCellContent);
+                return this.defaultCellContent;
         }
     }
+
+    render() {
+        return (
+            <div
+                className="schema-table-cell"
+                onPointerDown={action(e => {
+                    if (!this.selected) this.props.schemaView?.selectCell(this.props.Document, this.props.col);
+                })}
+                style={{ width: this.props.columnWidth, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
+                {this.content}
+            </div>
+        );
+    }
 }
 
 // mj: most of this is adapted from old schema code so I'm not sure what it does tbh
 @observer
-export class SchemaImageCell extends SchemaTableCell {
+export class SchemaImageCell extends React.Component<SchemaTableCellProps> {
     @observable _previewRef: HTMLImageElement | undefined;
 
     choosePath(url: URL) {
@@ -164,7 +186,7 @@ export class SchemaImageCell extends SchemaTableCell {
         document.body.removeChild(this._previewRef);
     };
 
-    get content() {
+    render() {
         const aspect = Doc.NativeAspect(this.props.Document); // aspect ratio
         // let width = Math.max(75, this.props.columnWidth); // get a with that is no smaller than 75px
         // const height = Math.max(75, width / aspect); // get a height either proportional to that or 75 px
@@ -173,14 +195,10 @@ export class SchemaImageCell extends SchemaTableCell {
 
         return <img src={this.url} width={width} height={height} style={{}} draggable="false" onPointerEnter={this.showHoverPreview} onPointerMove={this.moveHoverPreview} onPointerLeave={this.removeHoverPreview} />;
     }
-
-    render() {
-        return this.getCellWithContent(this.content);
-    }
 }
 
 @observer
-export class SchemaDateCell extends SchemaTableCell {
+export class SchemaDateCell extends React.Component<SchemaTableCellProps> {
     @observable _pickingDate: boolean = false;
 
     @computed get date(): DateField {
@@ -199,12 +217,7 @@ export class SchemaDateCell extends SchemaTableCell {
         //}
     };
 
-    get content() {
-        return <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
-        // return !this._pickingDate ? <div onPointerDown={action(() => (this._pickingDate = true))}>{this.defaultCellContent}</div> : <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
-    }
-
     render() {
-        return this.getCellWithContent(this.content);
+        return <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
     }
 }
-- 
cgit v1.2.3-70-g09d2


From b82a909a63a6de414d075735453240ebc02f5aa3 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Thu, 27 Apr 2023 13:20:52 -0400
Subject: fixed editing schema cells with keyboard only

---
 src/client/views/EditableView.tsx                  |  6 +++++
 .../collectionSchema/CollectionSchemaView.tsx      | 19 +++++++++------
 .../collections/collectionSchema/SchemaRowBox.tsx  |  6 +++--
 .../collectionSchema/SchemaTableCell.tsx           | 28 ++++++++++++++++------
 4 files changed, 43 insertions(+), 16 deletions(-)

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

diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 164b6c57a..d1311a60a 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -106,6 +106,12 @@ export class EditableView extends React.Component<EditableProps> {
             case ':':
                 this.props.menuCallback?.(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y);
                 break;
+            case 'ArrowUp':
+            case 'ArrowDown':
+            case 'ArrowLeft':
+            case 'ArrowRight':
+                e.stopPropagation();
+                break;
             case 'Shift':
             case 'Alt':
             case 'Meta':
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 92a04f5ec..8cd307adf 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,6 +1,6 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, ObservableMap, untracked } from 'mobx';
+import { action, computed, observable, ObservableMap, trace, untracked } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import { Doc, DocListCast, Field, StrListCast } from '../../../../fields/Doc';
@@ -170,12 +170,12 @@ export class CollectionSchemaView extends CollectionSubView() {
                         const lastDoc = this._selectedDocs.lastElement();
                         const lastIndex = this.rowIndex(lastDoc);
                         const curDoc = this.sortedDocs.docs[lastIndex];
-                        // const curDoc = this.childDocs[lastIndex];
                         if (lastIndex >= 0 && lastIndex < this.childDocs.length - 1) {
                             !e.shiftKey && this.clearSelection();
                             const newDoc = this.sortedDocs.docs[lastIndex + 1];
-                            if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc));
-                            else {
+                            if (this._selectedDocs.includes(newDoc)) {
+                                SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc));
+                            } else {
                                 this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1);
                                 this._selectedCell && (this._selectedCell[0] = newDoc);
                                 this.scrollToDoc(newDoc, {});
@@ -189,7 +189,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                     {
                         const firstDoc = this._selectedDocs.lastElement();
                         const firstIndex = this.rowIndex(firstDoc);
-                        // const curDoc = this.childDocs[firstIndex];
                         const curDoc = this.sortedDocs.docs[firstIndex];
                         if (firstIndex > 0 && firstIndex < this.childDocs.length) {
                             !e.shiftKey && this.clearSelection();
@@ -224,7 +223,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                     break;
                 }
                 case 'Escape': {
-                    this._selectedCell = undefined;
+                    this.deselectCell();
                 }
             }
         }
@@ -425,6 +424,11 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._selectedCell = [doc, index];
     };
 
+    @action
+    deselectCell = () => {
+        this._selectedCell = undefined;
+    };
+
     sortedSelectedDocs = () => this.sortedDocs.docs.filter(doc => this._selectedDocs.includes(doc));
 
     setDropIndex = (index: number) => (this._closestDropIndex = index);
@@ -456,7 +460,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             return true;
         }
         const draggedDocs = de.complete.docDragData?.draggedDocuments;
-        if (draggedDocs && super.onInternalDrop(e, de)) {
+        if (draggedDocs && super.onInternalDrop(e, de) && !this.sortField) {
             const pushedDocs = this.childDocs.filter((doc, index) => index >= this._closestDropIndex && !draggedDocs.includes(doc));
             const pushedAndDraggedDocs = [...pushedDocs, ...draggedDocs];
             const removed = this.childDocs.slice().filter(doc => !pushedAndDraggedDocs.includes(doc));
@@ -829,6 +833,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     @computed get sortedDocs() {
+        trace();
         const field = StrCast(this.layoutDoc.sortField);
         const desc = BoolCast(this.layoutDoc.sortDesc);
         const docs = !field
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index f5a16cec0..9864820a3 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -28,6 +28,8 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as CollectionSchemaView) : undefined;
     }
 
+    schemaViewFunc = () => this.schemaView;
+
     @computed get schemaDoc() {
         return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc;
     }
@@ -124,11 +126,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             key={key}
                             Document={this.rootDoc}
                             col={index}
-                            schemaView={this.schemaView}
+                            schemaView={this.schemaViewFunc}
                             fieldKey={key}
                             columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
                             isRowActive={this.props.isContentActive}
-                            setColumnValues={(field, value) => this.schemaView?.setColumnValues(field, value) ?? false}
+                            // setColumnValues={(field, value) => this.schemaView?.setColumnValues(field, value) ?? false}
                         />
                     ))}
                 </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 2b61ea261..374b92d72 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -21,11 +21,11 @@ import { SelectionManager } from '../../../util/SelectionManager';
 export interface SchemaTableCellProps {
     Document: Doc;
     col: number;
-    schemaView: CollectionSchemaView | undefined;
+    schemaView: () => CollectionSchemaView | undefined;
     fieldKey: string;
     columnWidth: number;
     isRowActive: () => boolean | undefined;
-    setColumnValues: (field: string, value: string) => boolean;
+    // setColumnValues: (field: string, value: string) => boolean;
 }
 
 @observer
@@ -33,20 +33,34 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     private _editorRef: EditableView | null = null;
 
     @computed get readOnly() {
-        return this.props.schemaView?.fieldInfos[this.props.fieldKey]?.readOnly ?? false;
+        return this.props.schemaView()?.fieldInfos[this.props.fieldKey]?.readOnly ?? false;
     }
 
     @computed get selected() {
-        const selected: [Doc, number] | undefined = this.props.schemaView?._selectedCell;
+        const selected: [Doc, number] | undefined = this.props.schemaView()?._selectedCell;
         return this.props.isRowActive() && selected && selected[0] == this.props.Document && selected[1] == this.props.col;
     }
 
     componentDidUpdate() {
         if (!this.selected) {
             this._editorRef?.setIsFocused(false);
+            document.removeEventListener('keydown', this.onKeyDown);
+        } else if (!this.readOnly) {
+            document.addEventListener('keydown', this.onKeyDown);
         }
     }
 
+    @action
+    onKeyDown = (e: KeyboardEvent) => {
+        e.stopPropagation();
+        if (e.key == 'Enter') {
+            this._editorRef?.setIsFocused(true);
+        }
+        if (e.key == 'Escape') {
+            this.props.schemaView()?.deselectCell();
+        }
+    };
+
     get defaultCellContent() {
         const props: FieldViewProps = {
             Document: this.props.Document,
@@ -81,7 +95,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
                     SetValue={(value: string, shiftDown?: boolean, enterKey?: boolean) => {
                         if (shiftDown && enterKey) {
-                            this.props.setColumnValues(this.props.fieldKey, value);
+                            // this.props.setColumnValues(this.props.fieldKey, value);
                         }
                         return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
                     }}
@@ -92,7 +106,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     }
 
     get getCellType() {
-        const columnTypeStr = this.props.schemaView?.fieldInfos[this.props.fieldKey]?.fieldType;
+        const columnTypeStr = this.props.schemaView()?.fieldInfos[this.props.fieldKey]?.fieldType;
         if (columnTypeStr) {
             if (columnTypeStr in FInfotoColType) {
                 return FInfotoColType[columnTypeStr];
@@ -125,7 +139,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             <div
                 className="schema-table-cell"
                 onPointerDown={action(e => {
-                    if (!this.selected) this.props.schemaView?.selectCell(this.props.Document, this.props.col);
+                    if (!this.selected) this.props.schemaView()?.selectCell(this.props.Document, this.props.col);
                 })}
                 style={{ width: this.props.columnWidth, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
                 {this.content}
-- 
cgit v1.2.3-70-g09d2


From ba5b687011526188bb024ddf37c254aaf285c06d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 27 Apr 2023 16:45:59 -0400
Subject: performance tuning for schema views to avoid re-rendering each table
 cell when child docs change.

---
 .../collectionLinear/CollectionLinearView.tsx      |  20 ++--
 .../collectionSchema/CollectionSchemaView.tsx      | 105 +++++++++------------
 .../collections/collectionSchema/SchemaRowBox.tsx  |  19 ++--
 .../collectionSchema/SchemaTableCell.tsx           |  48 +++++-----
 4 files changed, 94 insertions(+), 98 deletions(-)

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

diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index 97eed7752..efd73a927 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -255,15 +255,17 @@ export class CollectionLinearView extends CollectionSubView() {
                         })}
                     />
 
-                    <div
-                        className="collectionLinearView-content"
-                        style={{
-                            height: this.dimension(),
-                            flexDirection: flexDir as any,
-                            gap: flexGap,
-                        }}>
-                        {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))}
-                    </div>
+                    {!this.layoutDoc.linearViewIsExpanded ? null : (
+                        <div
+                            className="collectionLinearView-content"
+                            style={{
+                                height: this.dimension(),
+                                flexDirection: flexDir as any,
+                                gap: flexGap,
+                            }}>
+                            {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))}
+                        </div>
+                    )}
                 </div>
             </div>
         );
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 8cd307adf..50a91a60a 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,9 +1,9 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, ObservableMap, trace, untracked } from 'mobx';
+import { action, computed, observable, ObservableMap, observe, reaction, trace, untracked } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
-import { Doc, DocListCast, Field, StrListCast } from '../../../../fields/Doc';
+import { Doc, DocListCast, Field, NumListCast, StrListCast } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { listSpec } from '../../../../fields/Schema';
@@ -47,6 +47,7 @@ const defaultColumnKeys: string[] = ['title', 'type', 'author', 'creationDate',
 
 @observer
 export class CollectionSchemaView extends CollectionSubView() {
+    private _keysDisposer: any;
     private _closestDropIndex: number = 0;
     private _previewRef: HTMLDivElement | null = null;
     private _makeNewColumn: boolean = false;
@@ -58,15 +59,13 @@ export class CollectionSchemaView extends CollectionSubView() {
     public static _rowMenuWidth: number = 60;
     public static _previewDividerWidth: number = 4;
     public static _newNodeInputHeight: number = 30;
+    public fieldInfos = new ObservableMap<string, FInfo>();
 
-    @computed get _selectedDocs() {
-        return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.context), this.props.Document));
-    }
+    @observable _menuKeys: string[] = [];
     @observable _rowEles: ObservableMap = new ObservableMap<Doc, HTMLDivElement>();
     @observable _colEles: HTMLDivElement[] = [];
     @observable _displayColumnWidths: number[] | undefined;
     @observable _columnMenuIndex: number | undefined;
-    @observable _fieldInfos: [string, FInfo][] = [];
     @observable _newFieldWarning: string = '';
     @observable _makeNewField: boolean = false;
     @observable _newFieldDefault: any = 0;
@@ -76,34 +75,12 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _filterSearchValue: string = '';
     @observable _selectedCell: [Doc, number] | undefined;
 
-    get fieldInfos() {
-        const docs = this.childDocs;
-        const keys: { [key: string]: boolean } = {};
-        // bcz: ugh.  this is untracked since otherwise a large collection of documents will blast the server for all their fields.
-        //  then as each document's fields come back, we update the documents _proxies.  Each time we do this, the whole schema will be
-        //  invalidated and re-rendered.   This workaround will inquire all of the document fields before the options button is clicked.
-        //  then by the time the options button is clicked, all of the fields should be in place.  If a new field is added while this menu
-        //  is displayed (unlikely) it won't show up until something else changes.
-        //TODO Types
-        untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false)))));
-
-        let computedKeys: { [key: string]: FInfo } = {};
-
-        Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => {
-            computedKeys[pair[0]] = pair[1];
-        });
-
-        Object.keys(keys).forEach((key: string) => {
-            if (!(key in computedKeys)) {
-                computedKeys[key] = new FInfo('');
-            }
-        });
-
-        return computedKeys;
+    @computed get _selectedDocs() {
+        return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.context), this.rootDoc));
     }
 
-    get documentKeys() {
-        return Object.keys(this.fieldInfos);
+    @computed get documentKeys() {
+        return Array.from(this.fieldInfos.keys());
     }
 
     @computed get previewWidth() {
@@ -119,20 +96,15 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     @computed get storedColumnWidths() {
-        let widths = Cast(
+        const widths = NumListCast(
             this.layoutDoc.columnWidths,
-            listSpec('number'),
             this.columnKeys.map(() => (this.tableWidth - CollectionSchemaView._rowMenuWidth) / this.columnKeys.length)
         );
 
         const totalWidth = widths.reduce((sum, width) => sum + width, 0);
         if (totalWidth !== this.tableWidth - CollectionSchemaView._rowMenuWidth) {
-            widths = widths.map(w => {
-                const proportion = w / totalWidth;
-                return proportion * (this.tableWidth - CollectionSchemaView._rowMenuWidth);
-            });
+            return widths.map(w => (w / totalWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth));
         }
-
         return widths;
     }
 
@@ -148,19 +120,37 @@ export class CollectionSchemaView extends CollectionSubView() {
         return BoolCast(this.layoutDoc.sortDesc);
     }
 
-    rowIndex(doc: Doc) {
-        return this.sortedDocs.docs.indexOf(doc);
-    }
-
+    @action
     componentDidMount() {
         this.props.setContentView?.(this);
         document.addEventListener('keydown', this.onKeyDown);
+
+        Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => this.fieldInfos.set(pair[0], pair[1]));
+        this._keysDisposer = observe(
+            this.rootDoc[this.fieldKey ?? 'data'] as List<Doc>,
+            change => {
+                switch (change.type as any) {
+                    case 'splice':
+                        // prettier-ignore
+                        (change as any).added.forEach((doc: Doc) => // for each document added 
+                            Doc.GetAllPrototypes(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(''))))));
+                        break;
+                    case 'update': //let oldValue = change.oldValue; // fill this in if the entire child list will ever be reassigned with a new list
+                }
+            },
+            true
+        );
     }
 
     componentWillUnmount() {
+        this._keysDisposer?.();
         document.removeEventListener('keydown', this.onKeyDown);
     }
 
+    rowIndex = (doc: Doc) => this.sortedDocs.docs.indexOf(doc);
+
     @action
     onKeyDown = (e: KeyboardEvent) => {
         if (this._selectedDocs.length > 0) {
@@ -554,8 +544,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     onSearchKeyDown = (e: React.KeyboardEvent) => {
         switch (e.key) {
             case 'Enter':
-                const menuKeys = Object.keys(this._fieldInfos);
-                menuKeys.length > 0 && this._menuValue.length > 0 ? this.setKey(menuKeys[0]) : action(() => (this._makeNewField = true))();
+                this._menuKeys.length > 0 && this._menuValue.length > 0 ? this.setKey(this._menuKeys[0]) : action(() => (this._makeNewField = true))();
                 break;
             case 'Escape':
                 this.closeColumnMenu();
@@ -584,7 +573,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._makeNewColumn = false;
         this._columnMenuIndex = index;
         this._menuValue = '';
-        this._fieldInfos = Object.entries(this.fieldInfos);
+        this._menuKeys = this.documentKeys;
         this._makeNewField = false;
         this._newFieldWarning = '';
         this._makeNewField = false;
@@ -630,7 +619,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     updateKeySearch = (e: React.ChangeEvent<HTMLInputElement>) => {
         this._menuValue = e.target.value;
-        this._fieldInfos = Object.entries(this.fieldInfos).filter(value => value[0].toLowerCase().includes(this._menuValue.toLowerCase()));
+        this._menuKeys = this.documentKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
     };
 
     getFieldFilters = (field: string) => StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field);
@@ -732,7 +721,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                             { passive: false }
                         )
                     }>
-                    {this._fieldInfos.map(([key, info]) => (
+                    {this._menuKeys.map(key => (
                         <div
                             className="schema-search-result"
                             onPointerDown={e => {
@@ -742,13 +731,13 @@ export class CollectionSchemaView extends CollectionSubView() {
                             <p>
                                 <span className="schema-search-result-key">
                                     {key}
-                                    {info.fieldType ? ', ' : ''}
+                                    {this.fieldInfos.get(key)!.fieldType ? ', ' : ''}
                                 </span>
-                                <span className="schema-search-result-type" style={{ color: info.readOnly ? 'red' : 'inherit' }}>
-                                    {info.fieldType}
+                                <span className="schema-search-result-type" style={{ color: this.fieldInfos.get(key)!.readOnly ? 'red' : 'inherit' }}>
+                                    {this.fieldInfos.get(key)!.fieldType}
                                 </span>
                             </p>
-                            <p className="schema-search-result-desc">{info.description}</p>
+                            <p className="schema-search-result-desc">{this.fieldInfos.get(key)!.description}</p>
                         </div>
                     ))}
                 </div>
@@ -888,13 +877,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                     </div>
                     {this._columnMenuIndex !== undefined && this.renderColumnMenu}
                     {this._filterColumnIndex !== undefined && this.renderFilterMenu}
-                    <CollectionSchemaViewDocs
-                        schema={this}
-                        childDocs={this.sortedDocsFunc}
-                        setRef={(ref: HTMLDivElement | null) => {
-                            this._tableContentRef = ref;
-                        }}
-                    />
+                    <CollectionSchemaViewDocs schema={this} childDocs={this.sortedDocsFunc} setRef={(ref: HTMLDivElement | null) => (this._tableContentRef = ref)} />
                     <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} height={CollectionSchemaView._newNodeInputHeight} />
                 </div>
                 {this.previewWidth > 0 && <div className="schema-preview-divider" style={{ width: CollectionSchemaView._previewDividerWidth }} onPointerDown={this.onDividerDown}></div>}
@@ -923,7 +906,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 moveDocument={this.props.moveDocument}
                                 addDocument={this.addRow}
                                 removeDocument={this.props.removeDocument}
-                                whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
+                                whenChildContentsActiveChanged={returnFalse}
                                 addDocTab={this.props.addDocTab}
                                 pinToPres={this.props.pinToPres}
                                 bringToFront={returnFalse}
@@ -978,7 +961,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 bringToFront={emptyFunction}
                                 isDocumentActive={this.props.schema.props.childDocumentsActive?.() ? this.props.schema.props.isDocumentActive : this.props.schema.isContentActive}
                                 isContentActive={emptyFunction}
-                                whenChildContentsActiveChanged={active => this.props.schema.props.whenChildContentsActiveChanged(active)}
+                                whenChildContentsActiveChanged={this.props.schema.props.whenChildContentsActiveChanged}
                                 hideDecorations={true}
                                 hideTitle={true}
                                 hideDocumentButtonBar={true}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 9864820a3..9772ce118 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -12,6 +12,8 @@ import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { CollectionSchemaView } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
+import { computedFn } from 'mobx-utils';
+import { Doc } from '../../../../fields/Doc';
 
 @observer
 export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -24,12 +26,9 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
     bounds = () => this._ref?.getBoundingClientRect();
 
     @computed get schemaView() {
-        const vpath = this.props.docViewPath();
-        return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as CollectionSchemaView) : undefined;
+        return this.props.DocumentView?.().props.docViewPath().lastElement()?.ComponentView as CollectionSchemaView;
     }
 
-    schemaViewFunc = () => this.schemaView;
-
     @computed get schemaDoc() {
         return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc;
     }
@@ -86,6 +85,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         document.removeEventListener('pointermove', this.onPointerMove);
     };
 
+    getFinfo = computedFn((fieldKey: string) => this.schemaView?.fieldInfos.get(fieldKey));
+    selectCell = (doc: Doc, col: number) => this.schemaView?.selectCell(doc, col);
+    deselectCell = () => this.schemaView?.deselectCell();
+    selectedCell = () => this.schemaView?._selectedCell;
+    setColumnValues = (field: any, value: any) => this.schemaView?.setColumnValues(field, value) ?? false;
     render() {
         return (
             <div
@@ -126,11 +130,14 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             key={key}
                             Document={this.rootDoc}
                             col={index}
-                            schemaView={this.schemaViewFunc}
                             fieldKey={key}
                             columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
                             isRowActive={this.props.isContentActive}
-                            // setColumnValues={(field, value) => this.schemaView?.setColumnValues(field, value) ?? false}
+                            getFinfo={this.getFinfo}
+                            selectCell={this.selectCell}
+                            deselectCell={this.deselectCell}
+                            selectedCell={this.selectedCell}
+                            setColumnValues={this.setColumnValues}
                         />
                     ))}
                 </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 374b92d72..686b21283 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -1,31 +1,34 @@
 import React = require('react');
+import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
-import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../../Utils';
+import { extname } from 'path';
+import DatePicker from 'react-datepicker';
+import { DateField } from '../../../../fields/DateField';
+import { Doc, DocListCast, Field } from '../../../../fields/Doc';
+import { Cast, DateCast } from '../../../../fields/Types';
+import { ImageField } from '../../../../fields/URLField';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero, Utils } from '../../../../Utils';
 import { Transform } from '../../../util/Transform';
 import { EditableView } from '../../EditableView';
+import { Colors } from '../../global/globalEnums';
 import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { KeyValueBox } from '../../nodes/KeyValueBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
 import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
-import { action, computed, observable } from 'mobx';
-import { extname } from 'path';
-import { Cast, DateCast, StrCast } from '../../../../fields/Types';
-import { ImageField } from '../../../../fields/URLField';
-import { DateField } from '../../../../fields/DateField';
-import DatePicker from 'react-datepicker';
-import { Colors } from '../../global/globalEnums';
-import { SelectionManager } from '../../../util/SelectionManager';
+import { FInfo } from '../../../documents/Documents';
 
 export interface SchemaTableCellProps {
     Document: Doc;
     col: number;
-    schemaView: () => CollectionSchemaView | undefined;
+    deselectCell: () => void;
+    selectCell: (doc: Doc, col: number) => void;
+    selectedCell: () => [Doc, number] | undefined;
     fieldKey: string;
     columnWidth: number;
     isRowActive: () => boolean | undefined;
-    // setColumnValues: (field: string, value: string) => boolean;
+    getFinfo: (fieldKey: string) => FInfo | undefined;
+    setColumnValues: (field: string, value: string) => boolean;
 }
 
 @observer
@@ -33,11 +36,11 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     private _editorRef: EditableView | null = null;
 
     @computed get readOnly() {
-        return this.props.schemaView()?.fieldInfos[this.props.fieldKey]?.readOnly ?? false;
+        return this.props.getFinfo(this.props.fieldKey)?.readOnly ?? false;
     }
 
     @computed get selected() {
-        const selected: [Doc, number] | undefined = this.props.schemaView()?._selectedCell;
+        const selected: [Doc, number] | undefined = this.props.selectedCell();
         return this.props.isRowActive() && selected && selected[0] == this.props.Document && selected[1] == this.props.col;
     }
 
@@ -57,11 +60,12 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             this._editorRef?.setIsFocused(true);
         }
         if (e.key == 'Escape') {
-            this.props.schemaView()?.deselectCell();
+            this.props.deselectCell();
         }
     };
-
-    get defaultCellContent() {
+    colWidthFunc = () => this.props.columnWidth;
+    colRowHeightFunc = () => CollectionSchemaView._rowHeight;
+    @computed get defaultCellContent() {
         const props: FieldViewProps = {
             Document: this.props.Document,
             docFilters: returnEmptyFilter,
@@ -81,8 +85,8 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             whenChildContentsActiveChanged: emptyFunction,
             ScreenToLocalTransform: Transform.Identity,
             focus: emptyFunction,
-            PanelWidth: () => this.props.columnWidth,
-            PanelHeight: () => CollectionSchemaView._rowHeight,
+            PanelWidth: this.colWidthFunc,
+            PanelHeight: this.colRowHeightFunc,
             addDocTab: returnFalse,
             pinToPres: returnZero,
         };
@@ -95,7 +99,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
                     SetValue={(value: string, shiftDown?: boolean, enterKey?: boolean) => {
                         if (shiftDown && enterKey) {
-                            // this.props.setColumnValues(this.props.fieldKey, value);
+                            this.props.setColumnValues(this.props.fieldKey, value);
                         }
                         return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
                     }}
@@ -106,7 +110,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     }
 
     get getCellType() {
-        const columnTypeStr = this.props.schemaView()?.fieldInfos[this.props.fieldKey]?.fieldType;
+        const columnTypeStr = this.props.getFinfo(this.props.fieldKey)?.fieldType;
         if (columnTypeStr) {
             if (columnTypeStr in FInfotoColType) {
                 return FInfotoColType[columnTypeStr];
@@ -139,7 +143,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             <div
                 className="schema-table-cell"
                 onPointerDown={action(e => {
-                    if (!this.selected) this.props.schemaView()?.selectCell(this.props.Document, this.props.col);
+                    if (!this.selected) this.props.selectCell(this.props.Document, this.props.col);
                 })}
                 style={{ width: this.props.columnWidth, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
                 {this.content}
-- 
cgit v1.2.3-70-g09d2


From 51fbd118b00f4baebeed989bcd33000ac345ec8c Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 27 Apr 2023 20:28:31 -0400
Subject: fixed retrieving fields in schema view.

---
 .../views/collections/collectionSchema/CollectionSchemaView.tsx     | 6 +++---
 1 file changed, 3 insertions(+), 3 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 50a91a60a..3dff8d769 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,6 +1,6 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, ObservableMap, observe, reaction, trace, untracked } from 'mobx';
+import { action, computed, observable, ObservableMap, observe, trace } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import { Doc, DocListCast, Field, NumListCast, StrListCast } from '../../../../fields/Doc';
@@ -16,6 +16,7 @@ import { SelectionManager } from '../../../util/SelectionManager';
 import { undoBatch } from '../../../util/UndoManager';
 import { ContextMenu } from '../../ContextMenu';
 import { EditableView } from '../../EditableView';
+import { Colors } from '../../global/globalEnums';
 import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView';
 import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
 import { KeyValueBox } from '../../nodes/KeyValueBox';
@@ -24,7 +25,6 @@ import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
-import { Colors } from '../../global/globalEnums';
 
 export enum ColumnType {
     Number,
@@ -134,7 +134,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                         // prettier-ignore
                         (change as any).added.forEach((doc: Doc) => // for each document added 
                             Doc.GetAllPrototypes(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
+                                Object.keys(proto.value as Doc).forEach(action(key => // check if any of its keys are new, and add them
                                     !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo(''))))));
                         break;
                     case 'update': //let oldValue = change.oldValue; // fill this in if the entire child list will ever be reassigned with a new list
-- 
cgit v1.2.3-70-g09d2


From c6fc5badaac451f16d9a537c8bda84e359bb0182 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 27 Apr 2023 23:11:25 -0400
Subject: another fix for fieldInfos

---
 .../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 3dff8d769..3f7e037d4 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -133,8 +133,8 @@ export class CollectionSchemaView extends CollectionSubView() {
                     case 'splice':
                         // prettier-ignore
                         (change as any).added.forEach((doc: Doc) => // for each document added 
-                            Doc.GetAllPrototypes(doc).forEach(proto => // for all of its prototypes (and itself)
-                                Object.keys(proto.value as Doc).forEach(action(key => // check if any of its keys are new, and add them
+                            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(''))))));
                         break;
                     case 'update': //let oldValue = change.oldValue; // fill this in if the entire child list will ever be reassigned with a new list
-- 
cgit v1.2.3-70-g09d2


From becc884883df07635f4619f908747598b3eb86ee Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 28 Apr 2023 09:57:53 -0400
Subject: added RTF cell type for schema.  fixed formatting DateFields so that
 they can be set from kvp/schema.  prevented on infinite loop possibility when
 setting proto to itself.

---
 src/Utils.ts                                       |  3 ++
 .../collectionSchema/CollectionSchemaView.tsx      | 15 ++++----
 .../collectionSchema/SchemaTableCell.tsx           | 40 ++++++++++++++++------
 src/client/views/nodes/KeyValueBox.tsx             |  2 +-
 src/fields/DateField.ts                            | 14 ++++----
 5 files changed, 48 insertions(+), 26 deletions(-)

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

diff --git a/src/Utils.ts b/src/Utils.ts
index 0c7deaf5d..73de6d754 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -513,6 +513,9 @@ export function returnTrue() {
     return true;
 }
 
+export function returnIgnore(): 'ignore' {
+    return 'ignore';
+}
 export function returnAlways(): 'always' {
     return 'always';
 }
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 3f7e037d4..a59d7e5a3 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -8,7 +8,7 @@ import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { listSpec } from '../../../../fields/Schema';
 import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, returnDefault, returnEmptyDoclist, returnEmptyString, returnFalse, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils';
+import { emptyFunction, returnDefault, 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';
@@ -32,6 +32,7 @@ export enum ColumnType {
     Boolean,
     Date,
     Image,
+    RTF,
     Any,
 }
 
@@ -41,6 +42,7 @@ export const FInfotoColType: { [key: string]: ColumnType } = {
     boolean: ColumnType.Boolean,
     date: ColumnType.Date,
     image: ColumnType.Image,
+    rtf: ColumnType.RTF,
 };
 
 const defaultColumnKeys: string[] = ['title', 'type', 'author', 'creationDate', 'text'];
@@ -410,14 +412,10 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     @action
-    selectCell = (doc: Doc, index: number) => {
-        this._selectedCell = [doc, index];
-    };
+    selectCell = (doc: Doc, index: number) => (this._selectedCell = [doc, index]);
 
     @action
-    deselectCell = () => {
-        this._selectedCell = undefined;
-    };
+    deselectCell = () => (this._selectedCell = undefined);
 
     sortedSelectedDocs = () => this.sortedDocs.docs.filter(doc => this._selectedDocs.includes(doc));
 
@@ -891,6 +889,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 dontCenter={'y'}
                                 onClickScriptDisable="always"
                                 focus={emptyFunction}
+                                defaultDoubleClick={returnIgnore}
                                 renderDepth={this.props.renderDepth + 1}
                                 rootSelected={this.rootSelected}
                                 PanelWidth={this.previewWidthFunc}
@@ -949,7 +948,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 PanelHeight={this.rowHeightFunc}
                                 styleProvider={DefaultStyleProvider}
                                 waitForDoubleClickToClick={returnNever}
-                                defaultDoubleClick={returnDefault}
+                                defaultDoubleClick={returnIgnore}
                                 enableDragWhenActive={true}
                                 onClickScriptDisable="always"
                                 focus={this.props.schema.focusDocument}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index f17f4a73c..712bd4491 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -5,7 +5,7 @@ import { extname } from 'path';
 import DatePicker from 'react-datepicker';
 import { DateField } from '../../../../fields/DateField';
 import { Doc, DocListCast, Field } from '../../../../fields/Doc';
-import { BoolCast, Cast, DateCast } from '../../../../fields/Types';
+import { BoolCast, Cast, DateCast, FieldValue } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero, Utils } from '../../../../Utils';
 import { FInfo } from '../../../documents/Documents';
@@ -19,6 +19,8 @@ import { KeyValueBox } from '../../nodes/KeyValueBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
 import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
+import { RichTextField } from '../../../../fields/RichTextField';
+import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
 
 export interface SchemaTableCellProps {
     Document: Doc;
@@ -113,18 +115,18 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     }
 
     get getCellType() {
-        const columnTypeStr = this.props.getFinfo(this.props.fieldKey)?.fieldType;
-        if (columnTypeStr) {
-            if (columnTypeStr in FInfotoColType) {
-                return FInfotoColType[columnTypeStr];
-            }
-
-            return ColumnType.Any;
-        }
-
         const cellValue = this.props.Document[this.props.fieldKey];
         if (cellValue instanceof ImageField) return ColumnType.Image;
         if (cellValue instanceof DateField) return ColumnType.Date;
+        if (cellValue instanceof RichTextField) return ColumnType.RTF;
+        if (typeof cellValue === 'number') return ColumnType.Any;
+        if (typeof cellValue === 'string') return ColumnType.Any;
+        if (typeof cellValue === 'boolean') return ColumnType.Any;
+
+        const columnTypeStr = this.props.getFinfo(this.props.fieldKey)?.fieldType;
+        if (columnTypeStr && columnTypeStr in FInfotoColType) {
+            return FInfotoColType[columnTypeStr];
+        }
 
         return ColumnType.Any;
     }
@@ -135,6 +137,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         switch (cellType) {
             case ColumnType.Image: return <SchemaImageCell {...this.props} />;
             case ColumnType.Boolean: return <SchemaBoolCell {...this.props} />;
+            case ColumnType.RTF: return <SchemaRTFCell {...this.props} />;
             case ColumnType.Date: // return <SchemaDateCell {...this.props} />;
             default:  return this.defaultCellContent;
         }
@@ -240,6 +243,23 @@ export class SchemaDateCell extends React.Component<SchemaTableCellProps> {
     }
 }
 @observer
+export class SchemaRTFCell extends React.Component<SchemaTableCellProps> {
+    @computed get selected() {
+        const selected: [Doc, number] | undefined = this.props.selectedCell();
+        return this.props.isRowActive() && selected?.[0] === this.props.Document && selected[1] === this.props.col;
+    }
+    selectedFunc = () => this.selected;
+    render() {
+        const { color, textDecoration, fieldProps, cursor, pointerEvents } = SchemaTableCell.renderProps(this.props);
+        fieldProps.isContentActive = this.selectedFunc;
+        return (
+            <div className="schemaRTFCell" style={{ display: 'flex', fontStyle: this.selected ? undefined : 'italic', width: '100%', height: '100%', position: 'relative', color, textDecoration, cursor, pointerEvents }}>
+                {this.selected ? <FormattedTextBox {...fieldProps} /> : (field => (field ? Field.toString(field) : ''))(FieldValue(fieldProps.Document[fieldProps.fieldKey]))}
+            </div>
+        );
+    }
+}
+@observer
 export class SchemaBoolCell extends React.Component<SchemaTableCellProps> {
     @computed get selected() {
         const selected: [Doc, number] | undefined = this.props.selectedCell();
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index b54364332..e317de11e 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -96,7 +96,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
             }
             field = res.result;
         }
-        if (Field.IsField(field, true)) {
+        if (Field.IsField(field, true) && (key !== 'proto' || field !== target)) {
             target[key] = field;
             return true;
         }
diff --git a/src/fields/DateField.ts b/src/fields/DateField.ts
index 26f51b2d3..2ea619bd9 100644
--- a/src/fields/DateField.ts
+++ b/src/fields/DateField.ts
@@ -1,11 +1,11 @@
-import { Deserializable } from "../client/util/SerializationHelper";
-import { serializable, date } from "serializr";
-import { ObjectField } from "./ObjectField";
-import { Copy, ToScriptString, ToString } from "./FieldSymbols";
-import { scriptingGlobal, ScriptingGlobals } from "../client/util/ScriptingGlobals";
+import { Deserializable } from '../client/util/SerializationHelper';
+import { serializable, date } from 'serializr';
+import { ObjectField } from './ObjectField';
+import { Copy, ToScriptString, ToString } from './FieldSymbols';
+import { scriptingGlobal, ScriptingGlobals } from '../client/util/ScriptingGlobals';
 
 @scriptingGlobal
-@Deserializable("date")
+@Deserializable('date')
 export class DateField extends ObjectField {
     @serializable(date())
     readonly date: Date;
@@ -24,7 +24,7 @@ export class DateField extends ObjectField {
     }
 
     [ToScriptString]() {
-        return `new DateField(new Date(${this.date.toISOString()}))`;
+        return `new DateField(new Date("${this.date.toISOString()}"))`;
     }
     [ToString]() {
         return this.date.toLocaleString();
-- 
cgit v1.2.3-70-g09d2

