From 19aa61f593c896f4d3bd0ffae6dbe306c2a9546d Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 10 Aug 2022 11:51:41 -0400
Subject: basic table in progress

---
 .../collectionSchema/SchemaColumnHeader.tsx        | 28 ++++++++++++++++++++++
 1 file changed, 28 insertions(+)
 create mode 100644 src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx

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

diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
new file mode 100644
index 000000000..9bd1b843f
--- /dev/null
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -0,0 +1,28 @@
+import React = require('react');
+import { observer } from 'mobx-react';
+import './CollectionSchemaView.scss';
+import { EditableView } from '../../EditableView';
+import { emptyFunction } from '../../../../Utils';
+import { action, computed } from 'mobx';
+
+export interface SchemaColumnHeaderProps {
+    columnKeys: string[];
+    columnWidths: number[];
+    columnIndex: number;
+    changeColumnKey: (index: number, newKey: string) => boolean;
+}
+
+@observer
+export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps> {
+    @computed get fieldKey() {
+        return this.props.columnKeys[this.props.columnIndex];
+    }
+
+    render() {
+        return (
+            <div className="schema-column-header" style={{ width: this.props.columnWidths[this.props.columnIndex] }}>
+                <EditableView SetValue={(newKey: string) => this.props.changeColumnKey(this.props.columnIndex, newKey)} GetValue={() => this.fieldKey} contents={this.fieldKey} />
+            </div>
+        );
+    }
+}
-- 
cgit v1.2.3-70-g09d2


From a20a40b86bf5df9200218cb713f48e593c41b0ae Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Tue, 16 Aug 2022 17:28:33 -0400
Subject: got formatter to work

---
 package-lock.json                                  | 1349 +++++++-------------
 .../collectionSchema/CollectionSchemaView.tsx      |    7 +-
 .../collectionSchema/SchemaColumnHeader.tsx        |    5 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  |   41 +-
 .../collectionSchema/SchemaTableCell.tsx           |    1 -
 5 files changed, 500 insertions(+), 903 deletions(-)

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

diff --git a/package-lock.json b/package-lock.json
index cafeebd3e..da921592a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5050,16 +5050,6 @@
             "integrity": "sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A==",
             "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-array": {
             "version": "2.12.1",
             "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
@@ -6112,8 +6102,8 @@
             "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw=="
         },
         "equation-editor-react": {
-            "version": "github:bobzel/equation-editor-react#75915e852b4b36a6a4cd3e1cbc80598da6b65227",
-            "from": "github:bobzel/equation-editor-react#useLocally",
+            "version": "git+ssh://git@github.com/bobzel/equation-editor-react.git#75915e852b4b36a6a4cd3e1cbc80598da6b65227",
+            "from": "equation-editor-react@github:bobzel/equation-editor-react#useLocally",
             "requires": {
                 "jquery": "^3.4.1",
                 "mathquill": "^0.10.1-a"
@@ -6210,9 +6200,9 @@
             }
         },
         "es5-ext": {
-            "version": "0.10.61",
-            "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz",
-            "integrity": "sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA==",
+            "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",
@@ -6229,6 +6219,18 @@
                 "d": "1",
                 "es5-ext": "^0.10.35",
                 "es6-symbol": "^3.1.1"
+            },
+            "dependencies": {
+                "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"
+                    }
+                }
             }
         },
         "es6-promise": {
@@ -6244,6 +6246,18 @@
             "requires": {
                 "d": "^1.0.1",
                 "ext": "^1.1.2"
+            },
+            "dependencies": {
+                "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"
+                    }
+                }
             }
         },
         "escalade": {
@@ -9500,14 +9514,14 @@
             "resolved": "https://registry.npmjs.org/image-size-stream/-/image-size-stream-1.1.0.tgz",
             "integrity": "sha512-N505B5FSy2Xf5l/Haef+99TwfJqTu40hnU560+rC0Cm6cxtwVz2yRFh9WpOk1YEjfv3dI0PgVYAH0hmXQmjDcw==",
             "requires": {
-                "image-size": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1",
+                "image-size": "image-size@git+https://github.com/netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1",
                 "readable-stream": "^1.0.33",
                 "tryit": "^1.0.1"
             },
             "dependencies": {
                 "image-size": {
-                    "version": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1",
-                    "from": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1"
+                    "version": "git+ssh://git@github.com/netroy/image-size.git#da2c863807a3e9602617bdd357b0de3ab4a064c1",
+                    "from": "image-size@git+https://github.com/netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1"
                 },
                 "isarray": {
                     "version": "0.0.1",
@@ -12505,70 +12519,59 @@
                 },
                 "abbrev": {
                     "version": "1.1.1",
-                    "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
-                    "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+                    "bundled": true
                 },
                 "agent-base": {
                     "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
-                    "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
+                    "bundled": true,
                     "requires": {
                         "es6-promisify": "^5.0.0"
                     }
                 },
                 "agentkeepalive": {
                     "version": "3.5.2",
-                    "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz",
-                    "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==",
+                    "bundled": true,
                     "requires": {
                         "humanize-ms": "^1.2.1"
                     }
                 },
                 "ansi-align": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz",
-                    "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=",
+                    "bundled": true,
                     "requires": {
                         "string-width": "^2.0.0"
                     }
                 },
                 "ansi-regex": {
                     "version": "2.1.1",
-                    "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
-                    "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+                    "bundled": true
                 },
                 "ansi-styles": {
                     "version": "3.2.1",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-                    "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+                    "bundled": true,
                     "requires": {
                         "color-convert": "^1.9.0"
                     }
                 },
                 "ansicolors": {
                     "version": "0.3.2",
-                    "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz",
-                    "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk="
+                    "bundled": true
                 },
                 "ansistyles": {
                     "version": "0.1.3",
-                    "resolved": "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz",
-                    "integrity": "sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk="
+                    "bundled": true
                 },
                 "aproba": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
-                    "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ=="
+                    "bundled": true
                 },
                 "archy": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
-                    "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA="
+                    "bundled": true
                 },
                 "are-we-there-yet": {
                     "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz",
-                    "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
+                    "bundled": true,
                     "requires": {
                         "delegates": "^1.0.0",
                         "readable-stream": "^2.0.6"
@@ -12576,8 +12579,7 @@
                     "dependencies": {
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -12590,8 +12592,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -12600,46 +12601,38 @@
                 },
                 "asap": {
                     "version": "2.0.6",
-                    "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
-                    "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
+                    "bundled": true
                 },
                 "asn1": {
                     "version": "0.2.4",
-                    "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
-                    "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+                    "bundled": true,
                     "requires": {
                         "safer-buffer": "~2.1.0"
                     }
                 },
                 "assert-plus": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
-                    "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+                    "bundled": true
                 },
                 "asynckit": {
                     "version": "0.4.0",
-                    "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-                    "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+                    "bundled": true
                 },
                 "aws-sign2": {
                     "version": "0.7.0",
-                    "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
-                    "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
+                    "bundled": true
                 },
                 "aws4": {
                     "version": "1.8.0",
-                    "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
-                    "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
+                    "bundled": true
                 },
                 "balanced-match": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-                    "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+                    "bundled": true
                 },
                 "bcrypt-pbkdf": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
-                    "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "tweetnacl": "^0.14.3"
@@ -12647,8 +12640,7 @@
                 },
                 "bin-links": {
                     "version": "1.1.8",
-                    "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-1.1.8.tgz",
-                    "integrity": "sha512-KgmVfx+QqggqP9dA3iIc5pA4T1qEEEL+hOhOhNPaUm77OTrJoOXE/C05SJLNJe6m/2wUK7F1tDSou7n5TfCDzQ==",
+                    "bundled": true,
                     "requires": {
                         "bluebird": "^3.5.3",
                         "cmd-shim": "^3.0.0",
@@ -12660,13 +12652,11 @@
                 },
                 "bluebird": {
                     "version": "3.5.5",
-                    "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz",
-                    "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w=="
+                    "bundled": true
                 },
                 "boxen": {
                     "version": "1.3.0",
-                    "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz",
-                    "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==",
+                    "bundled": true,
                     "requires": {
                         "ansi-align": "^2.0.0",
                         "camelcase": "^4.0.0",
@@ -12679,8 +12669,7 @@
                 },
                 "brace-expansion": {
                     "version": "1.1.11",
-                    "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-                    "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+                    "bundled": true,
                     "requires": {
                         "balanced-match": "^1.0.0",
                         "concat-map": "0.0.1"
@@ -12688,28 +12677,23 @@
                 },
                 "buffer-from": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz",
-                    "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA=="
+                    "bundled": true
                 },
                 "builtins": {
                     "version": "1.0.3",
-                    "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz",
-                    "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og="
+                    "bundled": true
                 },
                 "byline": {
                     "version": "5.0.0",
-                    "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz",
-                    "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE="
+                    "bundled": true
                 },
                 "byte-size": {
                     "version": "5.0.1",
-                    "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-5.0.1.tgz",
-                    "integrity": "sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw=="
+                    "bundled": true
                 },
                 "cacache": {
                     "version": "12.0.3",
-                    "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz",
-                    "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==",
+                    "bundled": true,
                     "requires": {
                         "bluebird": "^3.5.5",
                         "chownr": "^1.1.1",
@@ -12730,28 +12714,23 @@
                 },
                 "call-limit": {
                     "version": "1.1.1",
-                    "resolved": "https://registry.npmjs.org/call-limit/-/call-limit-1.1.1.tgz",
-                    "integrity": "sha512-5twvci5b9eRBw2wCfPtN0GmlR2/gadZqyFpPhOK6CvMFoFgA+USnZ6Jpu1lhG9h85pQ3Ouil3PfXWRD4EUaRiQ=="
+                    "bundled": true
                 },
                 "camelcase": {
                     "version": "4.1.0",
-                    "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
-                    "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
+                    "bundled": true
                 },
                 "capture-stack-trace": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz",
-                    "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0="
+                    "bundled": true
                 },
                 "caseless": {
                     "version": "0.12.0",
-                    "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
-                    "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+                    "bundled": true
                 },
                 "chalk": {
                     "version": "2.4.1",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
-                    "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+                    "bundled": true,
                     "requires": {
                         "ansi-styles": "^3.2.1",
                         "escape-string-regexp": "^1.0.5",
@@ -12760,31 +12739,26 @@
                 },
                 "chownr": {
                     "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
-                    "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
+                    "bundled": true
                 },
                 "ci-info": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
-                    "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
+                    "bundled": true
                 },
                 "cidr-regex": {
                     "version": "2.0.10",
-                    "resolved": "https://registry.npmjs.org/cidr-regex/-/cidr-regex-2.0.10.tgz",
-                    "integrity": "sha512-sB3ogMQXWvreNPbJUZMRApxuRYd+KoIo4RGQ81VatjmMW6WJPo+IJZ2846FGItr9VzKo5w7DXzijPLGtSd0N3Q==",
+                    "bundled": true,
                     "requires": {
                         "ip-regex": "^2.1.0"
                     }
                 },
                 "cli-boxes": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz",
-                    "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM="
+                    "bundled": true
                 },
                 "cli-columns": {
                     "version": "3.1.2",
-                    "resolved": "https://registry.npmjs.org/cli-columns/-/cli-columns-3.1.2.tgz",
-                    "integrity": "sha1-ZzLZcpee/CrkRKHwjgj6E5yWoY4=",
+                    "bundled": true,
                     "requires": {
                         "string-width": "^2.0.0",
                         "strip-ansi": "^3.0.1"
@@ -12792,8 +12766,7 @@
                 },
                 "cli-table3": {
                     "version": "0.5.1",
-                    "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz",
-                    "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==",
+                    "bundled": true,
                     "requires": {
                         "colors": "^1.1.2",
                         "object-assign": "^4.1.0",
@@ -12802,8 +12775,7 @@
                 },
                 "cliui": {
                     "version": "5.0.0",
-                    "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
-                    "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+                    "bundled": true,
                     "requires": {
                         "string-width": "^3.1.0",
                         "strip-ansi": "^5.2.0",
@@ -12812,18 +12784,15 @@
                     "dependencies": {
                         "ansi-regex": {
                             "version": "4.1.1",
-                            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
-                            "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="
+                            "bundled": true
                         },
                         "is-fullwidth-code-point": {
                             "version": "2.0.0",
-                            "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-                            "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+                            "bundled": true
                         },
                         "string-width": {
                             "version": "3.1.0",
-                            "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-                            "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+                            "bundled": true,
                             "requires": {
                                 "emoji-regex": "^7.0.1",
                                 "is-fullwidth-code-point": "^2.0.0",
@@ -12832,8 +12801,7 @@
                         },
                         "strip-ansi": {
                             "version": "5.2.0",
-                            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-                            "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+                            "bundled": true,
                             "requires": {
                                 "ansi-regex": "^4.1.0"
                             }
@@ -12842,13 +12810,11 @@
                 },
                 "clone": {
                     "version": "1.0.4",
-                    "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
-                    "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4="
+                    "bundled": true
                 },
                 "cmd-shim": {
                     "version": "3.0.3",
-                    "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-3.0.3.tgz",
-                    "integrity": "sha512-DtGg+0xiFhQIntSBRzL2fRQBnmtAVwXIDo4Qq46HPpObYquxMaZS4sb82U9nH91qJrlosC1wa9gwr0QyL/HypA==",
+                    "bundled": true,
                     "requires": {
                         "graceful-fs": "^4.1.2",
                         "mkdirp": "~0.5.0"
@@ -12856,32 +12822,27 @@
                 },
                 "code-point-at": {
                     "version": "1.1.0",
-                    "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
-                    "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+                    "bundled": true
                 },
                 "color-convert": {
                     "version": "1.9.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
-                    "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
+                    "bundled": true,
                     "requires": {
                         "color-name": "^1.1.1"
                     }
                 },
                 "color-name": {
                     "version": "1.1.3",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-                    "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+                    "bundled": true
                 },
                 "colors": {
                     "version": "1.3.3",
-                    "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz",
-                    "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==",
+                    "bundled": true,
                     "optional": true
                 },
                 "columnify": {
                     "version": "1.5.4",
-                    "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz",
-                    "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=",
+                    "bundled": true,
                     "requires": {
                         "strip-ansi": "^3.0.0",
                         "wcwidth": "^1.0.0"
@@ -12889,21 +12850,18 @@
                 },
                 "combined-stream": {
                     "version": "1.0.6",
-                    "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
-                    "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
+                    "bundled": true,
                     "requires": {
                         "delayed-stream": "~1.0.0"
                     }
                 },
                 "concat-map": {
                     "version": "0.0.1",
-                    "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-                    "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+                    "bundled": true
                 },
                 "concat-stream": {
                     "version": "1.6.2",
-                    "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
-                    "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+                    "bundled": true,
                     "requires": {
                         "buffer-from": "^1.0.0",
                         "inherits": "^2.0.3",
@@ -12913,8 +12871,7 @@
                     "dependencies": {
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -12927,8 +12884,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -12937,8 +12893,7 @@
                 },
                 "config-chain": {
                     "version": "1.1.12",
-                    "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz",
-                    "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==",
+                    "bundled": true,
                     "requires": {
                         "ini": "^1.3.4",
                         "proto-list": "~1.2.1"
@@ -12946,8 +12901,7 @@
                 },
                 "configstore": {
                     "version": "3.1.5",
-                    "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.5.tgz",
-                    "integrity": "sha512-nlOhI4+fdzoK5xmJ+NY+1gZK56bwEaWZr8fYuXohZ9Vkc1o3a4T/R3M+yE/w7x/ZVJ1zF8c+oaOvF0dztdUgmA==",
+                    "bundled": true,
                     "requires": {
                         "dot-prop": "^4.2.1",
                         "graceful-fs": "^4.1.2",
@@ -12959,13 +12913,11 @@
                 },
                 "console-control-strings": {
                     "version": "1.1.0",
-                    "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
-                    "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
+                    "bundled": true
                 },
                 "copy-concurrently": {
                     "version": "1.0.5",
-                    "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
-                    "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^1.1.1",
                         "fs-write-stream-atomic": "^1.0.8",
@@ -12977,33 +12929,28 @@
                     "dependencies": {
                         "aproba": {
                             "version": "1.2.0",
-                            "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
-                            "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+                            "bundled": true
                         },
                         "iferr": {
                             "version": "0.1.5",
-                            "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz",
-                            "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE="
+                            "bundled": true
                         }
                     }
                 },
                 "core-util-is": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
-                    "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+                    "bundled": true
                 },
                 "create-error-class": {
                     "version": "3.0.2",
-                    "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz",
-                    "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=",
+                    "bundled": true,
                     "requires": {
                         "capture-stack-trace": "^1.0.0"
                     }
                 },
                 "cross-spawn": {
                     "version": "5.1.0",
-                    "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
-                    "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+                    "bundled": true,
                     "requires": {
                         "lru-cache": "^4.0.1",
                         "shebang-command": "^1.2.0",
@@ -13012,8 +12959,7 @@
                     "dependencies": {
                         "lru-cache": {
                             "version": "4.1.5",
-                            "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
-                            "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+                            "bundled": true,
                             "requires": {
                                 "pseudomap": "^1.0.2",
                                 "yallist": "^2.1.2"
@@ -13021,104 +12967,87 @@
                         },
                         "yallist": {
                             "version": "2.1.2",
-                            "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
-                            "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
+                            "bundled": true
                         }
                     }
                 },
                 "crypto-random-string": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz",
-                    "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4="
+                    "bundled": true
                 },
                 "cyclist": {
                     "version": "0.2.2",
-                    "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz",
-                    "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA="
+                    "bundled": true
                 },
                 "dashdash": {
                     "version": "1.14.1",
-                    "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
-                    "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+                    "bundled": true,
                     "requires": {
                         "assert-plus": "^1.0.0"
                     }
                 },
                 "debug": {
                     "version": "3.1.0",
-                    "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-                    "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+                    "bundled": true,
                     "requires": {
                         "ms": "2.0.0"
                     },
                     "dependencies": {
                         "ms": {
                             "version": "2.0.0",
-                            "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-                            "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+                            "bundled": true
                         }
                     }
                 },
                 "debuglog": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz",
-                    "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI="
+                    "bundled": true
                 },
                 "decamelize": {
                     "version": "1.2.0",
-                    "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
-                    "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
+                    "bundled": true
                 },
                 "decode-uri-component": {
                     "version": "0.2.0",
-                    "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
-                    "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
+                    "bundled": true
                 },
                 "deep-extend": {
                     "version": "0.6.0",
-                    "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
-                    "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
+                    "bundled": true
                 },
                 "defaults": {
                     "version": "1.0.3",
-                    "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
-                    "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=",
+                    "bundled": true,
                     "requires": {
                         "clone": "^1.0.2"
                     }
                 },
                 "define-properties": {
                     "version": "1.1.3",
-                    "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
-                    "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+                    "bundled": true,
                     "requires": {
                         "object-keys": "^1.0.12"
                     }
                 },
                 "delayed-stream": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
-                    "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+                    "bundled": true
                 },
                 "delegates": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
-                    "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
+                    "bundled": true
                 },
                 "detect-indent": {
                     "version": "5.0.0",
-                    "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz",
-                    "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50="
+                    "bundled": true
                 },
                 "detect-newline": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz",
-                    "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I="
+                    "bundled": true
                 },
                 "dezalgo": {
                     "version": "1.0.3",
-                    "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz",
-                    "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=",
+                    "bundled": true,
                     "requires": {
                         "asap": "^2.0.0",
                         "wrappy": "1"
@@ -13126,26 +13055,22 @@
                 },
                 "dot-prop": {
                     "version": "4.2.1",
-                    "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz",
-                    "integrity": "sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==",
+                    "bundled": true,
                     "requires": {
                         "is-obj": "^1.0.0"
                     }
                 },
                 "dotenv": {
                     "version": "5.0.1",
-                    "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz",
-                    "integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow=="
+                    "bundled": true
                 },
                 "duplexer3": {
                     "version": "0.1.4",
-                    "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
-                    "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI="
+                    "bundled": true
                 },
                 "duplexify": {
                     "version": "3.6.0",
-                    "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz",
-                    "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==",
+                    "bundled": true,
                     "requires": {
                         "end-of-stream": "^1.0.0",
                         "inherits": "^2.0.1",
@@ -13155,8 +13080,7 @@
                     "dependencies": {
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -13169,8 +13093,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -13179,8 +13102,7 @@
                 },
                 "ecc-jsbn": {
                     "version": "0.1.2",
-                    "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
-                    "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "jsbn": "~0.1.0",
@@ -13189,52 +13111,44 @@
                 },
                 "editor": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz",
-                    "integrity": "sha1-YMf4e9YrzGqJT6jM1q+3gjok90I="
+                    "bundled": true
                 },
                 "emoji-regex": {
                     "version": "7.0.3",
-                    "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
-                    "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="
+                    "bundled": true
                 },
                 "encoding": {
                     "version": "0.1.12",
-                    "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
-                    "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
+                    "bundled": true,
                     "requires": {
                         "iconv-lite": "~0.4.13"
                     }
                 },
                 "end-of-stream": {
                     "version": "1.4.1",
-                    "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
-                    "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
+                    "bundled": true,
                     "requires": {
                         "once": "^1.4.0"
                     }
                 },
                 "env-paths": {
                     "version": "2.2.0",
-                    "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz",
-                    "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA=="
+                    "bundled": true
                 },
                 "err-code": {
                     "version": "1.1.2",
-                    "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz",
-                    "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA="
+                    "bundled": true
                 },
                 "errno": {
                     "version": "0.1.7",
-                    "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
-                    "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
+                    "bundled": true,
                     "requires": {
                         "prr": "~1.0.1"
                     }
                 },
                 "es-abstract": {
                     "version": "1.12.0",
-                    "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
-                    "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==",
+                    "bundled": true,
                     "requires": {
                         "es-to-primitive": "^1.1.1",
                         "function-bind": "^1.1.1",
@@ -13245,8 +13159,7 @@
                 },
                 "es-to-primitive": {
                     "version": "1.2.0",
-                    "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz",
-                    "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==",
+                    "bundled": true,
                     "requires": {
                         "is-callable": "^1.1.4",
                         "is-date-object": "^1.0.1",
@@ -13255,26 +13168,22 @@
                 },
                 "es6-promise": {
                     "version": "4.2.8",
-                    "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
-                    "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
+                    "bundled": true
                 },
                 "es6-promisify": {
                     "version": "5.0.0",
-                    "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
-                    "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
+                    "bundled": true,
                     "requires": {
                         "es6-promise": "^4.0.3"
                     }
                 },
                 "escape-string-regexp": {
                     "version": "1.0.5",
-                    "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-                    "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+                    "bundled": true
                 },
                 "execa": {
                     "version": "0.7.0",
-                    "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
-                    "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
+                    "bundled": true,
                     "requires": {
                         "cross-spawn": "^5.0.1",
                         "get-stream": "^3.0.0",
@@ -13287,40 +13196,33 @@
                     "dependencies": {
                         "get-stream": {
                             "version": "3.0.0",
-                            "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
-                            "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
+                            "bundled": true
                         }
                     }
                 },
                 "extend": {
                     "version": "3.0.2",
-                    "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
-                    "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+                    "bundled": true
                 },
                 "extsprintf": {
                     "version": "1.3.0",
-                    "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
-                    "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+                    "bundled": true
                 },
                 "fast-json-stable-stringify": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
-                    "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
+                    "bundled": true
                 },
                 "figgy-pudding": {
                     "version": "3.5.1",
-                    "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz",
-                    "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w=="
+                    "bundled": true
                 },
                 "find-npm-prefix": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz",
-                    "integrity": "sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA=="
+                    "bundled": true
                 },
                 "flush-write-stream": {
                     "version": "1.0.3",
-                    "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz",
-                    "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==",
+                    "bundled": true,
                     "requires": {
                         "inherits": "^2.0.1",
                         "readable-stream": "^2.0.4"
@@ -13328,8 +13230,7 @@
                     "dependencies": {
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -13342,8 +13243,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -13352,13 +13252,11 @@
                 },
                 "forever-agent": {
                     "version": "0.6.1",
-                    "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
-                    "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+                    "bundled": true
                 },
                 "form-data": {
                     "version": "2.3.2",
-                    "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
-                    "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
+                    "bundled": true,
                     "requires": {
                         "asynckit": "^0.4.0",
                         "combined-stream": "1.0.6",
@@ -13367,8 +13265,7 @@
                 },
                 "from2": {
                     "version": "2.3.0",
-                    "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
-                    "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
+                    "bundled": true,
                     "requires": {
                         "inherits": "^2.0.1",
                         "readable-stream": "^2.0.0"
@@ -13376,8 +13273,7 @@
                     "dependencies": {
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -13390,8 +13286,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -13400,16 +13295,14 @@
                 },
                 "fs-minipass": {
                     "version": "1.2.7",
-                    "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
-                    "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
+                    "bundled": true,
                     "requires": {
                         "minipass": "^2.6.0"
                     },
                     "dependencies": {
                         "minipass": {
                             "version": "2.9.0",
-                            "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
-                            "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "^5.1.2",
                                 "yallist": "^3.0.0"
@@ -13419,8 +13312,7 @@
                 },
                 "fs-vacuum": {
                     "version": "1.2.10",
-                    "resolved": "https://registry.npmjs.org/fs-vacuum/-/fs-vacuum-1.2.10.tgz",
-                    "integrity": "sha1-t2Kb7AekAxolSP35n17PHMizHjY=",
+                    "bundled": true,
                     "requires": {
                         "graceful-fs": "^4.1.2",
                         "path-is-inside": "^1.0.1",
@@ -13429,8 +13321,7 @@
                 },
                 "fs-write-stream-atomic": {
                     "version": "1.0.10",
-                    "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
-                    "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=",
+                    "bundled": true,
                     "requires": {
                         "graceful-fs": "^4.1.2",
                         "iferr": "^0.1.5",
@@ -13440,13 +13331,11 @@
                     "dependencies": {
                         "iferr": {
                             "version": "0.1.5",
-                            "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz",
-                            "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE="
+                            "bundled": true
                         },
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -13459,8 +13348,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -13469,18 +13357,15 @@
                 },
                 "fs.realpath": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-                    "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+                    "bundled": true
                 },
                 "function-bind": {
                     "version": "1.1.1",
-                    "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
-                    "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+                    "bundled": true
                 },
                 "gauge": {
                     "version": "2.7.4",
-                    "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
-                    "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^1.0.3",
                         "console-control-strings": "^1.0.0",
@@ -13494,13 +13379,11 @@
                     "dependencies": {
                         "aproba": {
                             "version": "1.2.0",
-                            "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
-                            "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+                            "bundled": true
                         },
                         "string-width": {
                             "version": "1.0.2",
-                            "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
-                            "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+                            "bundled": true,
                             "requires": {
                                 "code-point-at": "^1.0.0",
                                 "is-fullwidth-code-point": "^1.0.0",
@@ -13511,13 +13394,11 @@
                 },
                 "genfun": {
                     "version": "5.0.0",
-                    "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz",
-                    "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA=="
+                    "bundled": true
                 },
                 "gentle-fs": {
                     "version": "2.3.1",
-                    "resolved": "https://registry.npmjs.org/gentle-fs/-/gentle-fs-2.3.1.tgz",
-                    "integrity": "sha512-OlwBBwqCFPcjm33rF2BjW+Pr6/ll2741l+xooiwTCeaX2CA1ZuclavyMBe0/KlR21/XGsgY6hzEQZ15BdNa13Q==",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^1.1.2",
                         "chownr": "^1.1.2",
@@ -13534,41 +13415,35 @@
                     "dependencies": {
                         "aproba": {
                             "version": "1.2.0",
-                            "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
-                            "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+                            "bundled": true
                         },
                         "iferr": {
                             "version": "0.1.5",
-                            "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz",
-                            "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE="
+                            "bundled": true
                         }
                     }
                 },
                 "get-caller-file": {
                     "version": "2.0.5",
-                    "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-                    "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
+                    "bundled": true
                 },
                 "get-stream": {
                     "version": "4.1.0",
-                    "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
-                    "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+                    "bundled": true,
                     "requires": {
                         "pump": "^3.0.0"
                     }
                 },
                 "getpass": {
                     "version": "0.1.7",
-                    "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
-                    "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+                    "bundled": true,
                     "requires": {
                         "assert-plus": "^1.0.0"
                     }
                 },
                 "glob": {
                     "version": "7.1.6",
-                    "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-                    "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+                    "bundled": true,
                     "requires": {
                         "fs.realpath": "^1.0.0",
                         "inflight": "^1.0.4",
@@ -13580,16 +13455,14 @@
                 },
                 "global-dirs": {
                     "version": "0.1.1",
-                    "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz",
-                    "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=",
+                    "bundled": true,
                     "requires": {
                         "ini": "^1.3.4"
                     }
                 },
                 "got": {
                     "version": "6.7.1",
-                    "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz",
-                    "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=",
+                    "bundled": true,
                     "requires": {
                         "create-error-class": "^3.0.0",
                         "duplexer3": "^0.1.4",
@@ -13606,25 +13479,21 @@
                     "dependencies": {
                         "get-stream": {
                             "version": "3.0.0",
-                            "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
-                            "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
+                            "bundled": true
                         }
                     }
                 },
                 "graceful-fs": {
                     "version": "4.2.4",
-                    "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
-                    "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
+                    "bundled": true
                 },
                 "har-schema": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
-                    "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
+                    "bundled": true
                 },
                 "har-validator": {
                     "version": "5.1.5",
-                    "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
-                    "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
+                    "bundled": true,
                     "requires": {
                         "ajv": "^6.12.3",
                         "har-schema": "^2.0.0"
@@ -13632,8 +13501,7 @@
                     "dependencies": {
                         "ajv": {
                             "version": "6.12.6",
-                            "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
-                            "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+                            "bundled": true,
                             "requires": {
                                 "fast-deep-equal": "^3.1.1",
                                 "fast-json-stable-stringify": "^2.0.0",
@@ -13643,53 +13511,44 @@
                         },
                         "fast-deep-equal": {
                             "version": "3.1.3",
-                            "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
-                            "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+                            "bundled": true
                         },
                         "json-schema-traverse": {
                             "version": "0.4.1",
-                            "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
-                            "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+                            "bundled": true
                         }
                     }
                 },
                 "has": {
                     "version": "1.0.3",
-                    "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
-                    "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+                    "bundled": true,
                     "requires": {
                         "function-bind": "^1.1.1"
                     }
                 },
                 "has-flag": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-                    "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
+                    "bundled": true
                 },
                 "has-symbols": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
-                    "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q="
+                    "bundled": true
                 },
                 "has-unicode": {
                     "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
-                    "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
+                    "bundled": true
                 },
                 "hosted-git-info": {
                     "version": "2.8.9",
-                    "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
-                    "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="
+                    "bundled": true
                 },
                 "http-cache-semantics": {
                     "version": "3.8.1",
-                    "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz",
-                    "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w=="
+                    "bundled": true
                 },
                 "http-proxy-agent": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
-                    "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
+                    "bundled": true,
                     "requires": {
                         "agent-base": "4",
                         "debug": "3.1.0"
@@ -13697,8 +13556,7 @@
                 },
                 "http-signature": {
                     "version": "1.2.0",
-                    "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
-                    "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+                    "bundled": true,
                     "requires": {
                         "assert-plus": "^1.0.0",
                         "jsprim": "^1.2.2",
@@ -13707,8 +13565,7 @@
                 },
                 "https-proxy-agent": {
                     "version": "2.2.4",
-                    "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
-                    "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
+                    "bundled": true,
                     "requires": {
                         "agent-base": "^4.3.0",
                         "debug": "^3.1.0"
@@ -13716,52 +13573,44 @@
                 },
                 "humanize-ms": {
                     "version": "1.2.1",
-                    "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
-                    "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=",
+                    "bundled": true,
                     "requires": {
                         "ms": "^2.0.0"
                     }
                 },
                 "iconv-lite": {
                     "version": "0.4.23",
-                    "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
-                    "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
+                    "bundled": true,
                     "requires": {
                         "safer-buffer": ">= 2.1.2 < 3"
                     }
                 },
                 "iferr": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/iferr/-/iferr-1.0.2.tgz",
-                    "integrity": "sha512-9AfeLfji44r5TKInjhz3W9DyZI1zR1JAf2hVBMGhddAKPqBsupb89jGfbCTHIGZd6fGZl9WlHdn4AObygyMKwg=="
+                    "bundled": true
                 },
                 "ignore-walk": {
                     "version": "3.0.3",
-                    "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz",
-                    "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==",
+                    "bundled": true,
                     "requires": {
                         "minimatch": "^3.0.4"
                     }
                 },
                 "import-lazy": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
-                    "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM="
+                    "bundled": true
                 },
                 "imurmurhash": {
                     "version": "0.1.4",
-                    "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
-                    "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
+                    "bundled": true
                 },
                 "infer-owner": {
                     "version": "1.0.4",
-                    "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
-                    "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A=="
+                    "bundled": true
                 },
                 "inflight": {
                     "version": "1.0.6",
-                    "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-                    "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+                    "bundled": true,
                     "requires": {
                         "once": "^1.3.0",
                         "wrappy": "1"
@@ -13769,18 +13618,15 @@
                 },
                 "inherits": {
                     "version": "2.0.4",
-                    "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-                    "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+                    "bundled": true
                 },
                 "ini": {
                     "version": "1.3.8",
-                    "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
-                    "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
+                    "bundled": true
                 },
                 "init-package-json": {
                     "version": "1.10.3",
-                    "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-1.10.3.tgz",
-                    "integrity": "sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw==",
+                    "bundled": true,
                     "requires": {
                         "glob": "^7.1.1",
                         "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0",
@@ -13794,59 +13640,50 @@
                 },
                 "ip": {
                     "version": "1.1.5",
-                    "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
-                    "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
+                    "bundled": true
                 },
                 "ip-regex": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
-                    "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
+                    "bundled": true
                 },
                 "is-callable": {
                     "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
-                    "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA=="
+                    "bundled": true
                 },
                 "is-ci": {
                     "version": "1.2.1",
-                    "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz",
-                    "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==",
+                    "bundled": true,
                     "requires": {
                         "ci-info": "^1.5.0"
                     },
                     "dependencies": {
                         "ci-info": {
                             "version": "1.6.0",
-                            "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz",
-                            "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A=="
+                            "bundled": true
                         }
                     }
                 },
                 "is-cidr": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/is-cidr/-/is-cidr-3.0.0.tgz",
-                    "integrity": "sha512-8Xnnbjsb0x462VoYiGlhEi+drY8SFwrHiSYuzc/CEwco55vkehTaxAyIjEdpi3EMvLPPJAJi9FlzP+h+03gp0Q==",
+                    "bundled": true,
                     "requires": {
                         "cidr-regex": "^2.0.10"
                     }
                 },
                 "is-date-object": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
-                    "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="
+                    "bundled": true
                 },
                 "is-fullwidth-code-point": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
-                    "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+                    "bundled": true,
                     "requires": {
                         "number-is-nan": "^1.0.0"
                     }
                 },
                 "is-installed-globally": {
                     "version": "0.1.0",
-                    "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz",
-                    "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=",
+                    "bundled": true,
                     "requires": {
                         "global-dirs": "^0.1.0",
                         "is-path-inside": "^1.0.0"
@@ -13854,103 +13691,85 @@
                 },
                 "is-npm": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz",
-                    "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ="
+                    "bundled": true
                 },
                 "is-obj": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
-                    "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8="
+                    "bundled": true
                 },
                 "is-path-inside": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
-                    "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
+                    "bundled": true,
                     "requires": {
                         "path-is-inside": "^1.0.1"
                     }
                 },
                 "is-redirect": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
-                    "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ="
+                    "bundled": true
                 },
                 "is-regex": {
                     "version": "1.0.4",
-                    "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
-                    "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
+                    "bundled": true,
                     "requires": {
                         "has": "^1.0.1"
                     }
                 },
                 "is-retry-allowed": {
                     "version": "1.2.0",
-                    "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz",
-                    "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg=="
+                    "bundled": true
                 },
                 "is-stream": {
                     "version": "1.1.0",
-                    "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
-                    "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
+                    "bundled": true
                 },
                 "is-symbol": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz",
-                    "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==",
+                    "bundled": true,
                     "requires": {
                         "has-symbols": "^1.0.0"
                     }
                 },
                 "is-typedarray": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
-                    "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+                    "bundled": true
                 },
                 "isarray": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-                    "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+                    "bundled": true
                 },
                 "isexe": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-                    "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+                    "bundled": true
                 },
                 "isstream": {
                     "version": "0.1.2",
-                    "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
-                    "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+                    "bundled": true
                 },
                 "jsbn": {
                     "version": "0.1.1",
-                    "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
-                    "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+                    "bundled": true,
                     "optional": true
                 },
                 "json-parse-better-errors": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
-                    "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
+                    "bundled": true
                 },
                 "json-schema": {
                     "version": "0.4.0",
-                    "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
-                    "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
+                    "bundled": true
                 },
                 "json-stringify-safe": {
                     "version": "5.0.1",
-                    "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
-                    "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+                    "bundled": true
                 },
                 "jsonparse": {
                     "version": "1.3.1",
-                    "resolved": false,
-                    "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA="
+                    "bundled": true
                 },
                 "jsprim": {
                     "version": "1.4.2",
-                    "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
-                    "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
+                    "bundled": true,
                     "requires": {
                         "assert-plus": "1.0.0",
                         "extsprintf": "1.3.0",
@@ -13960,21 +13779,18 @@
                 },
                 "latest-version": {
                     "version": "3.1.0",
-                    "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz",
-                    "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=",
+                    "bundled": true,
                     "requires": {
                         "package-json": "^4.0.0"
                     }
                 },
                 "lazy-property": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/lazy-property/-/lazy-property-1.0.0.tgz",
-                    "integrity": "sha1-hN3Es3Bnm6i9TNz6TAa0PVcREUc="
+                    "bundled": true
                 },
                 "libcipm": {
                     "version": "4.0.8",
-                    "resolved": "https://registry.npmjs.org/libcipm/-/libcipm-4.0.8.tgz",
-                    "integrity": "sha512-IN3hh2yDJQtZZ5paSV4fbvJg4aHxCCg5tcZID/dSVlTuUiWktsgaldVljJv6Z5OUlYspx6xQkbR0efNodnIrOA==",
+                    "bundled": true,
                     "requires": {
                         "bin-links": "^1.1.2",
                         "bluebird": "^3.5.1",
@@ -13995,8 +13811,7 @@
                 },
                 "libnpm": {
                     "version": "3.0.1",
-                    "resolved": "https://registry.npmjs.org/libnpm/-/libnpm-3.0.1.tgz",
-                    "integrity": "sha512-d7jU5ZcMiTfBqTUJVZ3xid44fE5ERBm9vBnmhp2ECD2Ls+FNXWxHSkO7gtvrnbLO78gwPdNPz1HpsF3W4rjkBQ==",
+                    "bundled": true,
                     "requires": {
                         "bin-links": "^1.1.2",
                         "bluebird": "^3.5.3",
@@ -14022,8 +13837,7 @@
                 },
                 "libnpmaccess": {
                     "version": "3.0.2",
-                    "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-3.0.2.tgz",
-                    "integrity": "sha512-01512AK7MqByrI2mfC7h5j8N9V4I7MHJuk9buo8Gv+5QgThpOgpjB7sQBDDkeZqRteFb1QM/6YNdHfG7cDvfAQ==",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^2.0.0",
                         "get-stream": "^4.0.0",
@@ -14033,8 +13847,7 @@
                 },
                 "libnpmconfig": {
                     "version": "1.2.1",
-                    "resolved": "https://registry.npmjs.org/libnpmconfig/-/libnpmconfig-1.2.1.tgz",
-                    "integrity": "sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA==",
+                    "bundled": true,
                     "requires": {
                         "figgy-pudding": "^3.5.1",
                         "find-up": "^3.0.0",
@@ -14043,16 +13856,14 @@
                     "dependencies": {
                         "find-up": {
                             "version": "3.0.0",
-                            "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
-                            "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+                            "bundled": true,
                             "requires": {
                                 "locate-path": "^3.0.0"
                             }
                         },
                         "locate-path": {
                             "version": "3.0.0",
-                            "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
-                            "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+                            "bundled": true,
                             "requires": {
                                 "p-locate": "^3.0.0",
                                 "path-exists": "^3.0.0"
@@ -14060,31 +13871,27 @@
                         },
                         "p-limit": {
                             "version": "2.2.0",
-                            "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz",
-                            "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==",
+                            "bundled": true,
                             "requires": {
                                 "p-try": "^2.0.0"
                             }
                         },
                         "p-locate": {
                             "version": "3.0.0",
-                            "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
-                            "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+                            "bundled": true,
                             "requires": {
                                 "p-limit": "^2.0.0"
                             }
                         },
                         "p-try": {
                             "version": "2.2.0",
-                            "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-                            "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
+                            "bundled": true
                         }
                     }
                 },
                 "libnpmhook": {
                     "version": "5.0.3",
-                    "resolved": "https://registry.npmjs.org/libnpmhook/-/libnpmhook-5.0.3.tgz",
-                    "integrity": "sha512-UdNLMuefVZra/wbnBXECZPefHMGsVDTq5zaM/LgKNE9Keyl5YXQTnGAzEo+nFOpdRqTWI9LYi4ApqF9uVCCtuA==",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^2.0.0",
                         "figgy-pudding": "^3.4.1",
@@ -14094,8 +13901,7 @@
                 },
                 "libnpmorg": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/libnpmorg/-/libnpmorg-1.0.1.tgz",
-                    "integrity": "sha512-0sRUXLh+PLBgZmARvthhYXQAWn0fOsa6T5l3JSe2n9vKG/lCVK4nuG7pDsa7uMq+uTt2epdPK+a2g6btcY11Ww==",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^2.0.0",
                         "figgy-pudding": "^3.4.1",
@@ -14105,8 +13911,7 @@
                 },
                 "libnpmpublish": {
                     "version": "1.1.2",
-                    "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-1.1.2.tgz",
-                    "integrity": "sha512-2yIwaXrhTTcF7bkJKIKmaCV9wZOALf/gsTDxVSu/Gu/6wiG3fA8ce8YKstiWKTxSFNC0R7isPUb6tXTVFZHt2g==",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^2.0.0",
                         "figgy-pudding": "^3.5.1",
@@ -14121,8 +13926,7 @@
                 },
                 "libnpmsearch": {
                     "version": "2.0.2",
-                    "resolved": "https://registry.npmjs.org/libnpmsearch/-/libnpmsearch-2.0.2.tgz",
-                    "integrity": "sha512-VTBbV55Q6fRzTdzziYCr64+f8AopQ1YZ+BdPOv16UegIEaE8C0Kch01wo4s3kRTFV64P121WZJwgmBwrq68zYg==",
+                    "bundled": true,
                     "requires": {
                         "figgy-pudding": "^3.5.1",
                         "get-stream": "^4.0.0",
@@ -14131,8 +13935,7 @@
                 },
                 "libnpmteam": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/libnpmteam/-/libnpmteam-1.0.2.tgz",
-                    "integrity": "sha512-p420vM28Us04NAcg1rzgGW63LMM6rwe+6rtZpfDxCcXxM0zUTLl7nPFEnRF3JfFBF5skF/yuZDUthTsHgde8QA==",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^2.0.0",
                         "figgy-pudding": "^3.4.1",
@@ -14142,8 +13945,7 @@
                 },
                 "libnpx": {
                     "version": "10.2.4",
-                    "resolved": "https://registry.npmjs.org/libnpx/-/libnpx-10.2.4.tgz",
-                    "integrity": "sha512-BPc0D1cOjBeS8VIBKUu5F80s6njm0wbVt7CsGMrIcJ+SI7pi7V0uVPGpEMH9H5L8csOcclTxAXFE2VAsJXUhfA==",
+                    "bundled": true,
                     "requires": {
                         "dotenv": "^5.0.1",
                         "npm-package-arg": "^6.0.0",
@@ -14157,8 +13959,7 @@
                 },
                 "lock-verify": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/lock-verify/-/lock-verify-2.1.0.tgz",
-                    "integrity": "sha512-vcLpxnGvrqisKvLQ2C2v0/u7LVly17ak2YSgoK4PrdsYBXQIax19vhKiLfvKNFx7FRrpTnitrpzF/uuCMuorIg==",
+                    "bundled": true,
                     "requires": {
                         "npm-package-arg": "^6.1.0",
                         "semver": "^5.4.1"
@@ -14166,21 +13967,18 @@
                 },
                 "lockfile": {
                     "version": "1.0.4",
-                    "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz",
-                    "integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==",
+                    "bundled": true,
                     "requires": {
                         "signal-exit": "^3.0.2"
                     }
                 },
                 "lodash._baseindexof": {
                     "version": "3.1.0",
-                    "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz",
-                    "integrity": "sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw="
+                    "bundled": true
                 },
                 "lodash._baseuniq": {
                     "version": "4.6.0",
-                    "resolved": "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz",
-                    "integrity": "sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg=",
+                    "bundled": true,
                     "requires": {
                         "lodash._createset": "~4.0.0",
                         "lodash._root": "~3.0.0"
@@ -14188,87 +13986,72 @@
                 },
                 "lodash._bindcallback": {
                     "version": "3.0.1",
-                    "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz",
-                    "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4="
+                    "bundled": true
                 },
                 "lodash._cacheindexof": {
                     "version": "3.0.2",
-                    "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz",
-                    "integrity": "sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI="
+                    "bundled": true
                 },
                 "lodash._createcache": {
                     "version": "3.1.2",
-                    "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz",
-                    "integrity": "sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=",
+                    "bundled": true,
                     "requires": {
                         "lodash._getnative": "^3.0.0"
                     }
                 },
                 "lodash._createset": {
                     "version": "4.0.3",
-                    "resolved": "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz",
-                    "integrity": "sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY="
+                    "bundled": true
                 },
                 "lodash._getnative": {
                     "version": "3.9.1",
-                    "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
-                    "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U="
+                    "bundled": true
                 },
                 "lodash._root": {
                     "version": "3.0.1",
-                    "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz",
-                    "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI="
+                    "bundled": true
                 },
                 "lodash.clonedeep": {
                     "version": "4.5.0",
-                    "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
-                    "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
+                    "bundled": true
                 },
                 "lodash.restparam": {
                     "version": "3.6.1",
-                    "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz",
-                    "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU="
+                    "bundled": true
                 },
                 "lodash.union": {
                     "version": "4.6.0",
-                    "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz",
-                    "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg="
+                    "bundled": true
                 },
                 "lodash.uniq": {
                     "version": "4.5.0",
-                    "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
-                    "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M="
+                    "bundled": true
                 },
                 "lodash.without": {
                     "version": "4.4.0",
-                    "resolved": "https://registry.npmjs.org/lodash.without/-/lodash.without-4.4.0.tgz",
-                    "integrity": "sha1-PNRXSgC2e643OpS3SHcmQFB7eqw="
+                    "bundled": true
                 },
                 "lowercase-keys": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
-                    "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA=="
+                    "bundled": true
                 },
                 "lru-cache": {
                     "version": "5.1.1",
-                    "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
-                    "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+                    "bundled": true,
                     "requires": {
                         "yallist": "^3.0.2"
                     }
                 },
                 "make-dir": {
                     "version": "1.3.0",
-                    "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
-                    "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
+                    "bundled": true,
                     "requires": {
                         "pify": "^3.0.0"
                     }
                 },
                 "make-fetch-happen": {
                     "version": "5.0.2",
-                    "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz",
-                    "integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==",
+                    "bundled": true,
                     "requires": {
                         "agentkeepalive": "^3.4.1",
                         "cacache": "^12.0.0",
@@ -14285,47 +14068,40 @@
                 },
                 "meant": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/meant/-/meant-1.0.2.tgz",
-                    "integrity": "sha512-KN+1uowN/NK+sT/Lzx7WSGIj2u+3xe5n2LbwObfjOhPZiA+cCfCm6idVl0RkEfjThkw5XJ96CyRcanq6GmKtUg=="
+                    "bundled": true
                 },
                 "mime-db": {
                     "version": "1.35.0",
-                    "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz",
-                    "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg=="
+                    "bundled": true
                 },
                 "mime-types": {
                     "version": "2.1.19",
-                    "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz",
-                    "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==",
+                    "bundled": true,
                     "requires": {
                         "mime-db": "~1.35.0"
                     }
                 },
                 "minimatch": {
                     "version": "3.0.4",
-                    "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
-                    "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+                    "bundled": true,
                     "requires": {
                         "brace-expansion": "^1.1.7"
                     }
                 },
                 "minimist": {
                     "version": "1.2.6",
-                    "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
-                    "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
+                    "bundled": true
                 },
                 "minizlib": {
                     "version": "1.3.3",
-                    "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
-                    "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
+                    "bundled": true,
                     "requires": {
                         "minipass": "^2.9.0"
                     },
                     "dependencies": {
                         "minipass": {
                             "version": "2.9.0",
-                            "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
-                            "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "^5.1.2",
                                 "yallist": "^3.0.0"
@@ -14335,8 +14111,7 @@
                 },
                 "mississippi": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
-                    "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==",
+                    "bundled": true,
                     "requires": {
                         "concat-stream": "^1.5.0",
                         "duplexify": "^3.4.2",
@@ -14352,23 +14127,20 @@
                 },
                 "mkdirp": {
                     "version": "0.5.5",
-                    "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
-                    "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+                    "bundled": true,
                     "requires": {
                         "minimist": "^1.2.5"
                     },
                     "dependencies": {
                         "minimist": {
                             "version": "1.2.6",
-                            "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
-                            "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
+                            "bundled": true
                         }
                     }
                 },
                 "move-concurrently": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
-                    "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^1.1.1",
                         "copy-concurrently": "^1.0.0",
@@ -14380,25 +14152,21 @@
                     "dependencies": {
                         "aproba": {
                             "version": "1.2.0",
-                            "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
-                            "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+                            "bundled": true
                         }
                     }
                 },
                 "ms": {
                     "version": "2.1.1",
-                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
-                    "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+                    "bundled": true
                 },
                 "mute-stream": {
                     "version": "0.0.7",
-                    "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
-                    "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
+                    "bundled": true
                 },
                 "node-fetch-npm": {
                     "version": "2.0.2",
-                    "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz",
-                    "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==",
+                    "bundled": true,
                     "requires": {
                         "encoding": "^0.1.11",
                         "json-parse-better-errors": "^1.0.0",
@@ -14407,8 +14175,7 @@
                 },
                 "node-gyp": {
                     "version": "5.1.0",
-                    "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.0.tgz",
-                    "integrity": "sha512-OUTryc5bt/P8zVgNUmC6xdXiDJxLMAW8cF5tLQOT9E5sOQj+UeQxnnPy74K3CLCa/SOjjBlbuzDLR8ANwA+wmw==",
+                    "bundled": true,
                     "requires": {
                         "env-paths": "^2.2.0",
                         "glob": "^7.1.4",
@@ -14425,8 +14192,7 @@
                 },
                 "nopt": {
                     "version": "4.0.3",
-                    "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz",
-                    "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==",
+                    "bundled": true,
                     "requires": {
                         "abbrev": "1",
                         "osenv": "^0.1.4"
@@ -14434,8 +14200,7 @@
                 },
                 "normalize-package-data": {
                     "version": "2.5.0",
-                    "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
-                    "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+                    "bundled": true,
                     "requires": {
                         "hosted-git-info": "^2.1.4",
                         "resolve": "^1.10.0",
@@ -14445,8 +14210,7 @@
                     "dependencies": {
                         "resolve": {
                             "version": "1.10.0",
-                            "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",
-                            "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==",
+                            "bundled": true,
                             "requires": {
                                 "path-parse": "^1.0.6"
                             }
@@ -14455,8 +14219,7 @@
                 },
                 "npm-audit-report": {
                     "version": "1.3.3",
-                    "resolved": "https://registry.npmjs.org/npm-audit-report/-/npm-audit-report-1.3.3.tgz",
-                    "integrity": "sha512-8nH/JjsFfAWMvn474HB9mpmMjrnKb1Hx/oTAdjv4PT9iZBvBxiZ+wtDUapHCJwLqYGQVPaAfs+vL5+5k9QndXw==",
+                    "bundled": true,
                     "requires": {
                         "cli-table3": "^0.5.0",
                         "console-control-strings": "^1.1.0"
@@ -14464,29 +14227,25 @@
                 },
                 "npm-bundled": {
                     "version": "1.1.1",
-                    "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz",
-                    "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==",
+                    "bundled": true,
                     "requires": {
                         "npm-normalize-package-bin": "^1.0.1"
                     }
                 },
                 "npm-cache-filename": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz",
-                    "integrity": "sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE="
+                    "bundled": true
                 },
                 "npm-install-checks": {
                     "version": "3.0.2",
-                    "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-3.0.2.tgz",
-                    "integrity": "sha512-E4kzkyZDIWoin6uT5howP8VDvkM+E8IQDcHAycaAxMbwkqhIg5eEYALnXOl3Hq9MrkdQB/2/g1xwBINXdKSRkg==",
+                    "bundled": true,
                     "requires": {
                         "semver": "^2.3.0 || 3.x || 4 || 5"
                     }
                 },
                 "npm-lifecycle": {
                     "version": "3.1.5",
-                    "resolved": "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz",
-                    "integrity": "sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g==",
+                    "bundled": true,
                     "requires": {
                         "byline": "^5.0.0",
                         "graceful-fs": "^4.1.15",
@@ -14500,18 +14259,15 @@
                 },
                 "npm-logical-tree": {
                     "version": "1.2.1",
-                    "resolved": "https://registry.npmjs.org/npm-logical-tree/-/npm-logical-tree-1.2.1.tgz",
-                    "integrity": "sha512-AJI/qxDB2PWI4LG1CYN579AY1vCiNyWfkiquCsJWqntRu/WwimVrC8yXeILBFHDwxfOejxewlmnvW9XXjMlYIg=="
+                    "bundled": true
                 },
                 "npm-normalize-package-bin": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz",
-                    "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA=="
+                    "bundled": true
                 },
                 "npm-package-arg": {
                     "version": "6.1.1",
-                    "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz",
-                    "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==",
+                    "bundled": true,
                     "requires": {
                         "hosted-git-info": "^2.7.1",
                         "osenv": "^0.1.5",
@@ -14521,8 +14277,7 @@
                 },
                 "npm-packlist": {
                     "version": "1.4.8",
-                    "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz",
-                    "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==",
+                    "bundled": true,
                     "requires": {
                         "ignore-walk": "^3.0.1",
                         "npm-bundled": "^1.0.1",
@@ -14531,8 +14286,7 @@
                 },
                 "npm-pick-manifest": {
                     "version": "3.0.2",
-                    "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz",
-                    "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==",
+                    "bundled": true,
                     "requires": {
                         "figgy-pudding": "^3.5.1",
                         "npm-package-arg": "^6.0.0",
@@ -14541,8 +14295,7 @@
                 },
                 "npm-profile": {
                     "version": "4.0.4",
-                    "resolved": "https://registry.npmjs.org/npm-profile/-/npm-profile-4.0.4.tgz",
-                    "integrity": "sha512-Ta8xq8TLMpqssF0H60BXS1A90iMoM6GeKwsmravJ6wYjWwSzcYBTdyWa3DZCYqPutacBMEm7cxiOkiIeCUAHDQ==",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^1.1.2 || 2",
                         "figgy-pudding": "^3.4.1",
@@ -14551,8 +14304,7 @@
                 },
                 "npm-registry-fetch": {
                     "version": "4.0.7",
-                    "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.7.tgz",
-                    "integrity": "sha512-cny9v0+Mq6Tjz+e0erFAB+RYJ/AVGzkjnISiobqP8OWj9c9FLoZZu8/SPSKJWE17F1tk4018wfjV+ZbIbqC7fQ==",
+                    "bundled": true,
                     "requires": {
                         "JSONStream": "^1.3.4",
                         "bluebird": "^3.5.1",
@@ -14565,28 +14317,24 @@
                     "dependencies": {
                         "safe-buffer": {
                             "version": "5.2.1",
-                            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-                            "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+                            "bundled": true
                         }
                     }
                 },
                 "npm-run-path": {
                     "version": "2.0.2",
-                    "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
-                    "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+                    "bundled": true,
                     "requires": {
                         "path-key": "^2.0.0"
                     }
                 },
                 "npm-user-validate": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-1.0.1.tgz",
-                    "integrity": "sha512-uQwcd/tY+h1jnEaze6cdX/LrhWhoBxfSknxentoqmIuStxUExxjWd3ULMLFPiFUrZKbOVMowH6Jq2FRWfmhcEw=="
+                    "bundled": true
                 },
                 "npmlog": {
                     "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
-                    "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+                    "bundled": true,
                     "requires": {
                         "are-we-there-yet": "~1.1.2",
                         "console-control-strings": "~1.1.0",
@@ -14596,28 +14344,23 @@
                 },
                 "number-is-nan": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
-                    "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+                    "bundled": true
                 },
                 "oauth-sign": {
                     "version": "0.9.0",
-                    "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
-                    "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
+                    "bundled": true
                 },
                 "object-assign": {
                     "version": "4.1.1",
-                    "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-                    "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+                    "bundled": true
                 },
                 "object-keys": {
                     "version": "1.0.12",
-                    "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
-                    "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag=="
+                    "bundled": true
                 },
                 "object.getownpropertydescriptors": {
                     "version": "2.0.3",
-                    "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",
-                    "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=",
+                    "bundled": true,
                     "requires": {
                         "define-properties": "^1.1.2",
                         "es-abstract": "^1.5.1"
@@ -14625,31 +14368,26 @@
                 },
                 "once": {
                     "version": "1.4.0",
-                    "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-                    "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+                    "bundled": true,
                     "requires": {
                         "wrappy": "1"
                     }
                 },
                 "opener": {
                     "version": "1.5.2",
-                    "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
-                    "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A=="
+                    "bundled": true
                 },
                 "os-homedir": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
-                    "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
+                    "bundled": true
                 },
                 "os-tmpdir": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
-                    "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
+                    "bundled": true
                 },
                 "osenv": {
                     "version": "0.1.5",
-                    "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
-                    "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+                    "bundled": true,
                     "requires": {
                         "os-homedir": "^1.0.0",
                         "os-tmpdir": "^1.0.0"
@@ -14657,13 +14395,11 @@
                 },
                 "p-finally": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
-                    "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
+                    "bundled": true
                 },
                 "package-json": {
                     "version": "4.0.1",
-                    "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz",
-                    "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=",
+                    "bundled": true,
                     "requires": {
                         "got": "^6.7.1",
                         "registry-auth-token": "^3.0.1",
@@ -14673,8 +14409,7 @@
                 },
                 "pacote": {
                     "version": "9.5.12",
-                    "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.12.tgz",
-                    "integrity": "sha512-BUIj/4kKbwWg4RtnBncXPJd15piFSVNpTzY0rysSr3VnMowTYgkGKcaHrbReepAkjTr8lH2CVWRi58Spg2CicQ==",
+                    "bundled": true,
                     "requires": {
                         "bluebird": "^3.5.3",
                         "cacache": "^12.0.2",
@@ -14710,8 +14445,7 @@
                     "dependencies": {
                         "minipass": {
                             "version": "2.9.0",
-                            "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
-                            "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "^5.1.2",
                                 "yallist": "^3.0.0"
@@ -14721,8 +14455,7 @@
                 },
                 "parallel-transform": {
                     "version": "1.1.0",
-                    "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz",
-                    "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=",
+                    "bundled": true,
                     "requires": {
                         "cyclist": "~0.2.2",
                         "inherits": "^2.0.3",
@@ -14731,8 +14464,7 @@
                     "dependencies": {
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -14745,8 +14477,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -14755,58 +14486,47 @@
                 },
                 "path-exists": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-                    "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
+                    "bundled": true
                 },
                 "path-is-absolute": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-                    "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+                    "bundled": true
                 },
                 "path-is-inside": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
-                    "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM="
+                    "bundled": true
                 },
                 "path-key": {
                     "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
-                    "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
+                    "bundled": true
                 },
                 "path-parse": {
                     "version": "1.0.7",
-                    "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
-                    "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
+                    "bundled": true
                 },
                 "performance-now": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
-                    "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+                    "bundled": true
                 },
                 "pify": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
-                    "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
+                    "bundled": true
                 },
                 "prepend-http": {
                     "version": "1.0.4",
-                    "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
-                    "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw="
+                    "bundled": true
                 },
                 "process-nextick-args": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
-                    "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
+                    "bundled": true
                 },
                 "promise-inflight": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
-                    "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM="
+                    "bundled": true
                 },
                 "promise-retry": {
                     "version": "1.1.1",
-                    "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz",
-                    "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=",
+                    "bundled": true,
                     "requires": {
                         "err-code": "^1.0.0",
                         "retry": "^0.10.0"
@@ -14814,51 +14534,43 @@
                     "dependencies": {
                         "retry": {
                             "version": "0.10.1",
-                            "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz",
-                            "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q="
+                            "bundled": true
                         }
                     }
                 },
                 "promzard": {
                     "version": "0.3.0",
-                    "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz",
-                    "integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=",
+                    "bundled": true,
                     "requires": {
                         "read": "1"
                     }
                 },
                 "proto-list": {
                     "version": "1.2.4",
-                    "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
-                    "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk="
+                    "bundled": true
                 },
                 "protoduck": {
                     "version": "5.0.1",
-                    "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz",
-                    "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==",
+                    "bundled": true,
                     "requires": {
                         "genfun": "^5.0.0"
                     }
                 },
                 "prr": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
-                    "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY="
+                    "bundled": true
                 },
                 "pseudomap": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
-                    "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
+                    "bundled": true
                 },
                 "psl": {
                     "version": "1.1.29",
-                    "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz",
-                    "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ=="
+                    "bundled": true
                 },
                 "pump": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
-                    "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+                    "bundled": true,
                     "requires": {
                         "end-of-stream": "^1.1.0",
                         "once": "^1.3.1"
@@ -14866,8 +14578,7 @@
                 },
                 "pumpify": {
                     "version": "1.5.1",
-                    "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
-                    "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
+                    "bundled": true,
                     "requires": {
                         "duplexify": "^3.6.0",
                         "inherits": "^2.0.3",
@@ -14876,8 +14587,7 @@
                     "dependencies": {
                         "pump": {
                             "version": "2.0.1",
-                            "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
-                            "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+                            "bundled": true,
                             "requires": {
                                 "end-of-stream": "^1.1.0",
                                 "once": "^1.3.1"
@@ -14887,23 +14597,19 @@
                 },
                 "punycode": {
                     "version": "1.4.1",
-                    "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
-                    "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+                    "bundled": true
                 },
                 "qrcode-terminal": {
                     "version": "0.12.0",
-                    "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz",
-                    "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ=="
+                    "bundled": true
                 },
                 "qs": {
                     "version": "6.5.2",
-                    "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
-                    "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
+                    "bundled": true
                 },
                 "query-string": {
                     "version": "6.8.2",
-                    "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.8.2.tgz",
-                    "integrity": "sha512-J3Qi8XZJXh93t2FiKyd/7Ec6GNifsjKXUsVFkSBj/kjLsDylWhnCz4NT1bkPcKotttPW+QbKGqqPH8OoI2pdqw==",
+                    "bundled": true,
                     "requires": {
                         "decode-uri-component": "^0.2.0",
                         "split-on-first": "^1.0.0",
@@ -14912,13 +14618,11 @@
                 },
                 "qw": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/qw/-/qw-1.0.1.tgz",
-                    "integrity": "sha1-77/cdA+a0FQwRCassYNBLMi5ltQ="
+                    "bundled": true
                 },
                 "rc": {
                     "version": "1.2.8",
-                    "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
-                    "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+                    "bundled": true,
                     "requires": {
                         "deep-extend": "^0.6.0",
                         "ini": "~1.3.0",
@@ -14928,24 +14632,21 @@
                 },
                 "read": {
                     "version": "1.0.7",
-                    "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
-                    "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
+                    "bundled": true,
                     "requires": {
                         "mute-stream": "~0.0.4"
                     }
                 },
                 "read-cmd-shim": {
                     "version": "1.0.5",
-                    "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz",
-                    "integrity": "sha512-v5yCqQ/7okKoZZkBQUAfTsQ3sVJtXdNfbPnI5cceppoxEVLYA3k+VtV2omkeo8MS94JCy4fSiUwlRBAwCVRPUA==",
+                    "bundled": true,
                     "requires": {
                         "graceful-fs": "^4.1.2"
                     }
                 },
                 "read-installed": {
                     "version": "4.0.3",
-                    "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz",
-                    "integrity": "sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc=",
+                    "bundled": true,
                     "requires": {
                         "debuglog": "^1.0.1",
                         "graceful-fs": "^4.1.2",
@@ -14958,8 +14659,7 @@
                 },
                 "read-package-json": {
                     "version": "2.1.1",
-                    "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.1.tgz",
-                    "integrity": "sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A==",
+                    "bundled": true,
                     "requires": {
                         "glob": "^7.1.1",
                         "graceful-fs": "^4.1.2",
@@ -14970,8 +14670,7 @@
                 },
                 "read-package-tree": {
                     "version": "5.3.1",
-                    "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz",
-                    "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==",
+                    "bundled": true,
                     "requires": {
                         "read-package-json": "^2.0.0",
                         "readdir-scoped-modules": "^1.0.0",
@@ -14980,8 +14679,7 @@
                 },
                 "readable-stream": {
                     "version": "3.6.0",
-                    "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
-                    "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+                    "bundled": true,
                     "requires": {
                         "inherits": "^2.0.3",
                         "string_decoder": "^1.1.1",
@@ -14990,8 +14688,7 @@
                 },
                 "readdir-scoped-modules": {
                     "version": "1.1.0",
-                    "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz",
-                    "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==",
+                    "bundled": true,
                     "requires": {
                         "debuglog": "^1.0.1",
                         "dezalgo": "^1.0.0",
@@ -15001,8 +14698,7 @@
                 },
                 "registry-auth-token": {
                     "version": "3.4.0",
-                    "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz",
-                    "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==",
+                    "bundled": true,
                     "requires": {
                         "rc": "^1.1.6",
                         "safe-buffer": "^5.0.1"
@@ -15010,16 +14706,14 @@
                 },
                 "registry-url": {
                     "version": "3.1.0",
-                    "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz",
-                    "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=",
+                    "bundled": true,
                     "requires": {
                         "rc": "^1.0.1"
                     }
                 },
                 "request": {
                     "version": "2.88.0",
-                    "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
-                    "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+                    "bundled": true,
                     "requires": {
                         "aws-sign2": "~0.7.0",
                         "aws4": "^1.8.0",
@@ -15045,115 +14739,96 @@
                 },
                 "require-directory": {
                     "version": "2.1.1",
-                    "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-                    "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
+                    "bundled": true
                 },
                 "require-main-filename": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
-                    "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
+                    "bundled": true
                 },
                 "resolve-from": {
                     "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
-                    "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
+                    "bundled": true
                 },
                 "retry": {
                     "version": "0.12.0",
-                    "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
-                    "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs="
+                    "bundled": true
                 },
                 "rimraf": {
                     "version": "2.7.1",
-                    "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
-                    "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+                    "bundled": true,
                     "requires": {
                         "glob": "^7.1.3"
                     }
                 },
                 "run-queue": {
                     "version": "1.0.3",
-                    "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
-                    "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^1.1.1"
                     },
                     "dependencies": {
                         "aproba": {
                             "version": "1.2.0",
-                            "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
-                            "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+                            "bundled": true
                         }
                     }
                 },
                 "safe-buffer": {
                     "version": "5.1.2",
-                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-                    "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+                    "bundled": true
                 },
                 "safer-buffer": {
                     "version": "2.1.2",
-                    "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
-                    "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+                    "bundled": true
                 },
                 "semver": {
                     "version": "5.7.1",
-                    "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
-                    "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+                    "bundled": true
                 },
                 "semver-diff": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz",
-                    "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=",
+                    "bundled": true,
                     "requires": {
                         "semver": "^5.0.3"
                     }
                 },
                 "set-blocking": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
-                    "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+                    "bundled": true
                 },
                 "sha": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/sha/-/sha-3.0.0.tgz",
-                    "integrity": "sha512-DOYnM37cNsLNSGIG/zZWch5CKIRNoLdYUQTQlcgkRkoYIUwDYjqDyye16YcDZg/OPdcbUgTKMjc4SY6TB7ZAPw==",
+                    "bundled": true,
                     "requires": {
                         "graceful-fs": "^4.1.2"
                     }
                 },
                 "shebang-command": {
                     "version": "1.2.0",
-                    "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
-                    "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+                    "bundled": true,
                     "requires": {
                         "shebang-regex": "^1.0.0"
                     }
                 },
                 "shebang-regex": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
-                    "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
+                    "bundled": true
                 },
                 "signal-exit": {
                     "version": "3.0.2",
-                    "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
-                    "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+                    "bundled": true
                 },
                 "slide": {
                     "version": "1.1.6",
-                    "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz",
-                    "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc="
+                    "bundled": true
                 },
                 "smart-buffer": {
                     "version": "4.1.0",
-                    "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz",
-                    "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw=="
+                    "bundled": true
                 },
                 "socks": {
                     "version": "2.3.3",
-                    "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz",
-                    "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==",
+                    "bundled": true,
                     "requires": {
                         "ip": "1.1.5",
                         "smart-buffer": "^4.1.0"
@@ -15161,8 +14836,7 @@
                 },
                 "socks-proxy-agent": {
                     "version": "4.0.2",
-                    "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz",
-                    "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==",
+                    "bundled": true,
                     "requires": {
                         "agent-base": "~4.2.1",
                         "socks": "~2.3.2"
@@ -15170,8 +14844,7 @@
                     "dependencies": {
                         "agent-base": {
                             "version": "4.2.1",
-                            "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
-                            "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==",
+                            "bundled": true,
                             "requires": {
                                 "es6-promisify": "^5.0.0"
                             }
@@ -15180,13 +14853,11 @@
                 },
                 "sorted-object": {
                     "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/sorted-object/-/sorted-object-2.0.1.tgz",
-                    "integrity": "sha1-fWMfS9OnmKJK8d/8+/6DM3pd9fw="
+                    "bundled": true
                 },
                 "sorted-union-stream": {
                     "version": "2.1.3",
-                    "resolved": "https://registry.npmjs.org/sorted-union-stream/-/sorted-union-stream-2.1.3.tgz",
-                    "integrity": "sha1-x3lMfgd4gAUv9xqNSi27Sppjisc=",
+                    "bundled": true,
                     "requires": {
                         "from2": "^1.3.0",
                         "stream-iterate": "^1.1.0"
@@ -15194,8 +14865,7 @@
                     "dependencies": {
                         "from2": {
                             "version": "1.3.0",
-                            "resolved": "https://registry.npmjs.org/from2/-/from2-1.3.0.tgz",
-                            "integrity": "sha1-iEE7qqX5pZfP3pIh2GmGzTwGHf0=",
+                            "bundled": true,
                             "requires": {
                                 "inherits": "~2.0.1",
                                 "readable-stream": "~1.1.10"
@@ -15203,13 +14873,11 @@
                         },
                         "isarray": {
                             "version": "0.0.1",
-                            "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
-                            "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+                            "bundled": true
                         },
                         "readable-stream": {
                             "version": "1.1.14",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
-                            "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.1",
@@ -15219,15 +14887,13 @@
                         },
                         "string_decoder": {
                             "version": "0.10.31",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
-                            "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+                            "bundled": true
                         }
                     }
                 },
                 "spdx-correct": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz",
-                    "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==",
+                    "bundled": true,
                     "requires": {
                         "spdx-expression-parse": "^3.0.0",
                         "spdx-license-ids": "^3.0.0"
@@ -15235,13 +14901,11 @@
                 },
                 "spdx-exceptions": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz",
-                    "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg=="
+                    "bundled": true
                 },
                 "spdx-expression-parse": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
-                    "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+                    "bundled": true,
                     "requires": {
                         "spdx-exceptions": "^2.1.0",
                         "spdx-license-ids": "^3.0.0"
@@ -15249,18 +14913,15 @@
                 },
                 "spdx-license-ids": {
                     "version": "3.0.5",
-                    "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
-                    "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q=="
+                    "bundled": true
                 },
                 "split-on-first": {
                     "version": "1.1.0",
-                    "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
-                    "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw=="
+                    "bundled": true
                 },
                 "sshpk": {
                     "version": "1.14.2",
-                    "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
-                    "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
+                    "bundled": true,
                     "requires": {
                         "asn1": "~0.2.3",
                         "assert-plus": "^1.0.0",
@@ -15275,16 +14936,14 @@
                 },
                 "ssri": {
                     "version": "6.0.2",
-                    "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz",
-                    "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==",
+                    "bundled": true,
                     "requires": {
                         "figgy-pudding": "^3.5.1"
                     }
                 },
                 "stream-each": {
                     "version": "1.2.2",
-                    "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.2.tgz",
-                    "integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==",
+                    "bundled": true,
                     "requires": {
                         "end-of-stream": "^1.1.0",
                         "stream-shift": "^1.0.0"
@@ -15292,8 +14951,7 @@
                 },
                 "stream-iterate": {
                     "version": "1.2.0",
-                    "resolved": "https://registry.npmjs.org/stream-iterate/-/stream-iterate-1.2.0.tgz",
-                    "integrity": "sha1-K9fHcpbBcCpGSIuK1B95hl7s1OE=",
+                    "bundled": true,
                     "requires": {
                         "readable-stream": "^2.1.5",
                         "stream-shift": "^1.0.0"
@@ -15301,8 +14959,7 @@
                     "dependencies": {
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -15315,8 +14972,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -15325,18 +14981,15 @@
                 },
                 "stream-shift": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
-                    "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI="
+                    "bundled": true
                 },
                 "strict-uri-encode": {
                     "version": "2.0.0",
-                    "resolved": false,
-                    "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
+                    "bundled": true
                 },
                 "string-width": {
                     "version": "2.1.1",
-                    "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
-                    "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+                    "bundled": true,
                     "requires": {
                         "is-fullwidth-code-point": "^2.0.0",
                         "strip-ansi": "^4.0.0"
@@ -15344,18 +14997,15 @@
                     "dependencies": {
                         "ansi-regex": {
                             "version": "3.0.0",
-                            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-                            "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+                            "bundled": true
                         },
                         "is-fullwidth-code-point": {
                             "version": "2.0.0",
-                            "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-                            "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+                            "bundled": true
                         },
                         "strip-ansi": {
                             "version": "4.0.0",
-                            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
-                            "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+                            "bundled": true,
                             "requires": {
                                 "ansi-regex": "^3.0.0"
                             }
@@ -15377,39 +15027,33 @@
                 },
                 "stringify-package": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.1.tgz",
-                    "integrity": "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg=="
+                    "bundled": true
                 },
                 "strip-ansi": {
                     "version": "3.0.1",
-                    "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
-                    "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+                    "bundled": true,
                     "requires": {
                         "ansi-regex": "^2.0.0"
                     }
                 },
                 "strip-eof": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
-                    "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
+                    "bundled": true
                 },
                 "strip-json-comments": {
                     "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
-                    "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+                    "bundled": true
                 },
                 "supports-color": {
                     "version": "5.4.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
-                    "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
+                    "bundled": true,
                     "requires": {
                         "has-flag": "^3.0.0"
                     }
                 },
                 "tar": {
                     "version": "4.4.19",
-                    "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz",
-                    "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==",
+                    "bundled": true,
                     "requires": {
                         "chownr": "^1.1.4",
                         "fs-minipass": "^1.2.7",
@@ -15422,8 +15066,7 @@
                     "dependencies": {
                         "minipass": {
                             "version": "2.9.0",
-                            "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
-                            "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "^5.1.2",
                                 "yallist": "^3.0.0"
@@ -15431,38 +15074,32 @@
                         },
                         "safe-buffer": {
                             "version": "5.2.1",
-                            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-                            "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+                            "bundled": true
                         },
                         "yallist": {
                             "version": "3.1.1",
-                            "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
-                            "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
+                            "bundled": true
                         }
                     }
                 },
                 "term-size": {
                     "version": "1.2.0",
-                    "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz",
-                    "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=",
+                    "bundled": true,
                     "requires": {
                         "execa": "^0.7.0"
                     }
                 },
                 "text-table": {
                     "version": "0.2.0",
-                    "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
-                    "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
+                    "bundled": true
                 },
                 "through": {
                     "version": "2.3.8",
-                    "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
-                    "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+                    "bundled": true
                 },
                 "through2": {
                     "version": "2.0.3",
-                    "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
-                    "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
+                    "bundled": true,
                     "requires": {
                         "readable-stream": "^2.1.5",
                         "xtend": "~4.0.1"
@@ -15470,8 +15107,7 @@
                     "dependencies": {
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -15484,8 +15120,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -15494,18 +15129,15 @@
                 },
                 "timed-out": {
                     "version": "4.0.1",
-                    "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz",
-                    "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8="
+                    "bundled": true
                 },
                 "tiny-relative-date": {
                     "version": "1.3.0",
-                    "resolved": "https://registry.npmjs.org/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz",
-                    "integrity": "sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A=="
+                    "bundled": true
                 },
                 "tough-cookie": {
                     "version": "2.4.3",
-                    "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
-                    "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+                    "bundled": true,
                     "requires": {
                         "psl": "^1.1.24",
                         "punycode": "^1.4.1"
@@ -15513,71 +15145,60 @@
                 },
                 "tunnel-agent": {
                     "version": "0.6.0",
-                    "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
-                    "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+                    "bundled": true,
                     "requires": {
                         "safe-buffer": "^5.0.1"
                     }
                 },
                 "tweetnacl": {
                     "version": "0.14.5",
-                    "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
-                    "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+                    "bundled": true,
                     "optional": true
                 },
                 "typedarray": {
                     "version": "0.0.6",
-                    "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
-                    "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
+                    "bundled": true
                 },
                 "uid-number": {
                     "version": "0.0.6",
-                    "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz",
-                    "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE="
+                    "bundled": true
                 },
                 "umask": {
                     "version": "1.1.0",
-                    "resolved": "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz",
-                    "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0="
+                    "bundled": true
                 },
                 "unique-filename": {
                     "version": "1.1.1",
-                    "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
-                    "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==",
+                    "bundled": true,
                     "requires": {
                         "unique-slug": "^2.0.0"
                     }
                 },
                 "unique-slug": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz",
-                    "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=",
+                    "bundled": true,
                     "requires": {
                         "imurmurhash": "^0.1.4"
                     }
                 },
                 "unique-string": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz",
-                    "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=",
+                    "bundled": true,
                     "requires": {
                         "crypto-random-string": "^1.0.0"
                     }
                 },
                 "unpipe": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
-                    "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+                    "bundled": true
                 },
                 "unzip-response": {
                     "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz",
-                    "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c="
+                    "bundled": true
                 },
                 "update-notifier": {
                     "version": "2.5.0",
-                    "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz",
-                    "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==",
+                    "bundled": true,
                     "requires": {
                         "boxen": "^1.2.1",
                         "chalk": "^2.0.1",
@@ -15593,54 +15214,46 @@
                 },
                 "uri-js": {
                     "version": "4.4.0",
-                    "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
-                    "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
+                    "bundled": true,
                     "requires": {
                         "punycode": "^2.1.0"
                     },
                     "dependencies": {
                         "punycode": {
                             "version": "2.1.1",
-                            "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
-                            "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+                            "bundled": true
                         }
                     }
                 },
                 "url-parse-lax": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz",
-                    "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=",
+                    "bundled": true,
                     "requires": {
                         "prepend-http": "^1.0.1"
                     }
                 },
                 "util-deprecate": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-                    "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+                    "bundled": true
                 },
                 "util-extend": {
                     "version": "1.0.3",
-                    "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz",
-                    "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8="
+                    "bundled": true
                 },
                 "util-promisify": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz",
-                    "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=",
+                    "bundled": true,
                     "requires": {
                         "object.getownpropertydescriptors": "^2.0.3"
                     }
                 },
                 "uuid": {
                     "version": "3.3.3",
-                    "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
-                    "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ=="
+                    "bundled": true
                 },
                 "validate-npm-package-license": {
                     "version": "3.0.4",
-                    "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
-                    "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+                    "bundled": true,
                     "requires": {
                         "spdx-correct": "^3.0.0",
                         "spdx-expression-parse": "^3.0.0"
@@ -15648,16 +15261,14 @@
                 },
                 "validate-npm-package-name": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz",
-                    "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=",
+                    "bundled": true,
                     "requires": {
                         "builtins": "^1.0.3"
                     }
                 },
                 "verror": {
                     "version": "1.10.0",
-                    "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
-                    "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+                    "bundled": true,
                     "requires": {
                         "assert-plus": "^1.0.0",
                         "core-util-is": "1.0.2",
@@ -15666,37 +15277,32 @@
                 },
                 "wcwidth": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
-                    "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=",
+                    "bundled": true,
                     "requires": {
                         "defaults": "^1.0.3"
                     }
                 },
                 "which": {
                     "version": "1.3.1",
-                    "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
-                    "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+                    "bundled": true,
                     "requires": {
                         "isexe": "^2.0.0"
                     }
                 },
                 "which-module": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
-                    "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
+                    "bundled": true
                 },
                 "wide-align": {
                     "version": "1.1.2",
-                    "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz",
-                    "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
+                    "bundled": true,
                     "requires": {
                         "string-width": "^1.0.2"
                     },
                     "dependencies": {
                         "string-width": {
                             "version": "1.0.2",
-                            "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
-                            "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+                            "bundled": true,
                             "requires": {
                                 "code-point-at": "^1.0.0",
                                 "is-fullwidth-code-point": "^1.0.0",
@@ -15707,24 +15313,21 @@
                 },
                 "widest-line": {
                     "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz",
-                    "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==",
+                    "bundled": true,
                     "requires": {
                         "string-width": "^2.1.1"
                     }
                 },
                 "worker-farm": {
                     "version": "1.7.0",
-                    "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",
-                    "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==",
+                    "bundled": true,
                     "requires": {
                         "errno": "~0.1.7"
                     }
                 },
                 "wrap-ansi": {
                     "version": "5.1.0",
-                    "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
-                    "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+                    "bundled": true,
                     "requires": {
                         "ansi-styles": "^3.2.0",
                         "string-width": "^3.0.0",
@@ -15733,18 +15336,15 @@
                     "dependencies": {
                         "ansi-regex": {
                             "version": "4.1.1",
-                            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
-                            "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="
+                            "bundled": true
                         },
                         "is-fullwidth-code-point": {
                             "version": "2.0.0",
-                            "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-                            "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+                            "bundled": true
                         },
                         "string-width": {
                             "version": "3.1.0",
-                            "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-                            "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+                            "bundled": true,
                             "requires": {
                                 "emoji-regex": "^7.0.1",
                                 "is-fullwidth-code-point": "^2.0.0",
@@ -15753,8 +15353,7 @@
                         },
                         "strip-ansi": {
                             "version": "5.2.0",
-                            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-                            "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+                            "bundled": true,
                             "requires": {
                                 "ansi-regex": "^4.1.0"
                             }
@@ -15763,13 +15362,11 @@
                 },
                 "wrappy": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-                    "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+                    "bundled": true
                 },
                 "write-file-atomic": {
                     "version": "2.4.3",
-                    "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
-                    "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
+                    "bundled": true,
                     "requires": {
                         "graceful-fs": "^4.1.11",
                         "imurmurhash": "^0.1.4",
@@ -15778,28 +15375,23 @@
                 },
                 "xdg-basedir": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz",
-                    "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ="
+                    "bundled": true
                 },
                 "xtend": {
                     "version": "4.0.1",
-                    "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
-                    "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
+                    "bundled": true
                 },
                 "y18n": {
                     "version": "4.0.1",
-                    "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz",
-                    "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ=="
+                    "bundled": true
                 },
                 "yallist": {
                     "version": "3.0.3",
-                    "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
-                    "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
+                    "bundled": true
                 },
                 "yargs": {
                     "version": "14.2.3",
-                    "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz",
-                    "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==",
+                    "bundled": true,
                     "requires": {
                         "cliui": "^5.0.0",
                         "decamelize": "^1.2.0",
@@ -15816,26 +15408,22 @@
                     "dependencies": {
                         "ansi-regex": {
                             "version": "4.1.0",
-                            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
-                            "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
+                            "bundled": true
                         },
                         "find-up": {
                             "version": "3.0.0",
-                            "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
-                            "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+                            "bundled": true,
                             "requires": {
                                 "locate-path": "^3.0.0"
                             }
                         },
                         "is-fullwidth-code-point": {
                             "version": "2.0.0",
-                            "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-                            "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+                            "bundled": true
                         },
                         "locate-path": {
                             "version": "3.0.0",
-                            "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
-                            "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+                            "bundled": true,
                             "requires": {
                                 "p-locate": "^3.0.0",
                                 "path-exists": "^3.0.0"
@@ -15843,29 +15431,25 @@
                         },
                         "p-limit": {
                             "version": "2.3.0",
-                            "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-                            "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+                            "bundled": true,
                             "requires": {
                                 "p-try": "^2.0.0"
                             }
                         },
                         "p-locate": {
                             "version": "3.0.0",
-                            "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
-                            "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+                            "bundled": true,
                             "requires": {
                                 "p-limit": "^2.0.0"
                             }
                         },
                         "p-try": {
                             "version": "2.2.0",
-                            "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-                            "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
+                            "bundled": true
                         },
                         "string-width": {
                             "version": "3.1.0",
-                            "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-                            "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+                            "bundled": true,
                             "requires": {
                                 "emoji-regex": "^7.0.1",
                                 "is-fullwidth-code-point": "^2.0.0",
@@ -15874,8 +15458,7 @@
                         },
                         "strip-ansi": {
                             "version": "5.2.0",
-                            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-                            "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+                            "bundled": true,
                             "requires": {
                                 "ansi-regex": "^4.1.0"
                             }
@@ -15884,8 +15467,7 @@
                 },
                 "yargs-parser": {
                     "version": "15.0.1",
-                    "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz",
-                    "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==",
+                    "bundled": true,
                     "requires": {
                         "camelcase": "^5.0.0",
                         "decamelize": "^1.2.0"
@@ -15893,8 +15475,7 @@
                     "dependencies": {
                         "camelcase": {
                             "version": "5.3.1",
-                            "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-                            "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
+                            "bundled": true
                         }
                     }
                 }
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 02bc55e7a..bcfa695f0 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -88,11 +88,10 @@ export class CollectionSchemaView extends CollectionSubView() {
             this._selectedDocs.add(doc);
             this._lastSelectedRow = index;
         }
-        
+
         if (this._lastSelectedRow && this._selectedDocs.size > 0) {
             SelectionManager.SelectSchemaViewDoc(this.childDocs[this._lastSelectedRow]);
-        }
-        else {
+        } else {
             SelectionManager.SelectSchemaViewDoc(undefined);
         }
     };
@@ -154,7 +153,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
         if (!value && !forceEmptyNote) return false;
-        const newDoc = Docs.Create.TextDocument(value, {title: value});
+        const newDoc = Docs.Create.TextDocument(value, { title: value });
         FormattedTextBox.SelectOnLoad = newDoc[Id];
         FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? '' : ' ';
         return this.props.addDocument?.(newDoc) || false;
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 9bd1b843f..b9dbf4f57 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -1,9 +1,8 @@
 import React = require('react');
+import { computed } from 'mobx';
 import { observer } from 'mobx-react';
-import './CollectionSchemaView.scss';
 import { EditableView } from '../../EditableView';
-import { emptyFunction } from '../../../../Utils';
-import { action, computed } from 'mobx';
+import './CollectionSchemaView.scss';
 
 export interface SchemaColumnHeaderProps {
     columnKeys: string[];
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index ea2ebed7a..3d1fa0ee2 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -36,12 +36,13 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
         e.stopPropagation();
 
         setupMoveUpEvents(
-            this, e,
-            (e) => this.props.startDrag(e, this.props.Document),
+            this,
+            e,
+            e => this.props.startDrag(e, this.props.Document),
             emptyFunction,
-            (e) => this.props.selectRow(e, this.props.Document, this.props.rowIndex)
-        )
-    }
+            e => this.props.selectRow(e, this.props.Document, this.props.rowIndex)
+        );
+    };
 
     onPointerEnter = (e: any) => {
         if (!this.props.dragging) return;
@@ -54,7 +55,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
         let dragIsRow: boolean = true;
         DragManager.docsBeingDragged.forEach(doc => {
             dragIsRow = this.props.selectedRows.has(doc);
-        })
+        });
         if (this._ref && dragIsRow) {
             const rect = this._ref.getBoundingClientRect();
             const y = e.clientY - rect.top; //y position within the element.
@@ -82,17 +83,35 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
 
     render() {
         return (
-            <div className="schema-row" style={this.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE, opacity: this.props.dragging ? 0.5 : 1} : {}} onPointerDown={this.onRowPointerDown} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave} ref={(row: HTMLDivElement | null) => (this._ref = row)}>
-                <div className="row-menu" style={{width: this.props.rowMenuWidth}}>
-                    <div className="row-button" onPointerDown={undoBatch((e) => {e.stopPropagation(); this.props.removeDocument?.(this.props.Document)})}>
+            <div
+                className="schema-row"
+                style={this.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE, opacity: this.props.dragging ? 0.5 : 1 } : {}}
+                onPointerDown={this.onRowPointerDown}
+                onPointerEnter={this.onPointerEnter}
+                onPointerLeave={this.onPointerLeave}
+                ref={(row: HTMLDivElement | null) => (this._ref = row)}>
+                <div className="row-menu" style={{ width: this.props.rowMenuWidth }}>
+                    <div
+                        className="row-button"
+                        onPointerDown={undoBatch(e => {
+                            e.stopPropagation();
+                            this.props.removeDocument?.(this.props.Document);
+                        })}>
                         <FontAwesomeIcon icon="times" />
                     </div>
-                    <div className="row-button" onPointerDown={(e) => {e.stopPropagation(); this.props.addDocTab(this.props.Document, 'add:right')}}>
+                    <div
+                        className="row-button"
+                        onPointerDown={e => {
+                            e.stopPropagation();
+                            this.props.addDocTab(this.props.Document, 'add:right');
+                        }}>
                         <FontAwesomeIcon icon="external-link-alt" />
                     </div>
                 </div>
                 <div className="row-cells">
-                    {this.props.columnKeys.map((key, index) => (<SchemaTableCell Document={this.props.Document} fieldKey={key} columnWidth={this.props.columnWidths[index]} />))}
+                    {this.props.columnKeys.map((key, index) => (
+                        <SchemaTableCell Document={this.props.Document} fieldKey={key} columnWidth={this.props.columnWidths[index]} />
+                    ))}
                 </div>
             </div>
         );
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 1eb5e0e01..7e2fa1f6f 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -1,7 +1,6 @@
 import React = require('react');
 import { observer } from 'mobx-react';
 import { Doc, Field } from '../../../../fields/Doc';
-import { StrCast } from '../../../../fields/Types';
 import './CollectionSchemaView.scss';
 
 export interface SchemaTableCellProps {
-- 
cgit v1.2.3-70-g09d2


From fb1e291b1bed4b60a645030b4a79c0760ba73fdc Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Tue, 16 Aug 2022 18:10:15 -0400
Subject: add and remove columns (remove buggy for same named headers)

---
 .vscode/settings.json                              |  5 ++-
 .../collectionSchema/CollectionSchemaView.scss     | 40 +++++++++++++++-------
 .../collectionSchema/CollectionSchemaView.tsx      | 20 +++++++++--
 .../collectionSchema/SchemaColumnHeader.tsx        | 20 +++++++++++
 4 files changed, 69 insertions(+), 16 deletions(-)

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

diff --git a/.vscode/settings.json b/.vscode/settings.json
index f0cebd6fd..8849f30dd 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -10,5 +10,8 @@
     "editor.detectIndentation": false,
     "search.usePCRE2": true,
     "typescript.tsdk": "node_modules/typescript/lib",
-    "editor.defaultFormatter": "esbenp.prettier-vscode"
+    "editor.defaultFormatter": "esbenp.prettier-vscode",
+    "[typescriptreact]": {
+        "editor.defaultFormatter": "esbenp.prettier-vscode"
+    }
 }
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 4f644717b..83164a82a 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -27,6 +27,10 @@
 
             .schema-column-header {
                 font-weight: bold;
+                display: flex;
+                flex-direction: row;
+                justify-content: space-between;
+                align-items: center;
             }
         }
 
@@ -37,19 +41,6 @@
                 display: flex;
                 flex-direction: row;
                 justify-content: center;
-
-                .row-button {
-                    width: 25px;
-                    height: 25px;
-                    border-radius: 100%;
-                    background-color: $dark-gray;
-                    color: white;
-                    margin: 3px;
-                    cursor: pointer;
-                    display: flex;
-                    align-items: center;
-                    justify-content: center;
-                }
             }
 
             .row-cells {
@@ -58,5 +49,28 @@
                 justify-content: flex-end;
             }
         }
+
+        .schema-header-menu {
+            display: flex;
+            flex-direction: row;
+        }
+
+        .row-button,
+        .schema-header-button {
+            width: 20px;
+            height: 20px;
+            border-radius: 100%;
+            background-color: $dark-gray;
+            color: white;
+            margin: 3px;
+            cursor: pointer;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+
+            svg {
+                width: 12px;
+            }
+        }
     }
 }
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index bcfa695f0..4d96d5f7e 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -55,8 +55,8 @@ export class CollectionSchemaView extends CollectionSubView() {
         );
     }
 
-    @action
     @undoBatch
+    @action
     changeColumnKey = (index: number, newKey: string) => {
         let currKeys = this.columnKeys;
         currKeys[index] = newKey;
@@ -64,6 +64,22 @@ export class CollectionSchemaView extends CollectionSubView() {
         return true;
     };
 
+    @undoBatch
+    @action
+    addColumn = (index: number) => {
+        let currKeys = this.columnKeys;
+        currKeys.splice(index, 0, 'title');
+        this.layoutDoc.columnKeys = new List<string>(currKeys);
+    };
+
+    @undoBatch
+    @action
+    removeColumn = (index: number) => {
+        let currKeys = this.columnKeys;
+        currKeys.splice(index, 1);
+        this.layoutDoc.columnKeys = new List<string>(currKeys);
+    };
+
     @action
     selectRow = (e: React.PointerEvent, doc: Doc, index: number) => {
         const ctrl = e.ctrlKey || e.metaKey;
@@ -239,7 +255,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                 <div className="schema-table">
                     <div className="schema-header-row">
                         {this.columnKeys.map((key, index) => (
-                            <SchemaColumnHeader columnIndex={index} columnKeys={this.columnKeys} columnWidths={this.columnWidths} changeColumnKey={this.changeColumnKey} />
+                            <SchemaColumnHeader columnIndex={index} columnKeys={this.columnKeys} columnWidths={this.columnWidths} changeColumnKey={this.changeColumnKey} addColumn={this.addColumn} removeColumn={this.removeColumn} />
                         ))}
                     </div>
                     <div className="schema-table-content">
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index b9dbf4f57..f93a3d13d 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -3,12 +3,15 @@ import { computed } from 'mobx';
 import { observer } from 'mobx-react';
 import { EditableView } from '../../EditableView';
 import './CollectionSchemaView.scss';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 
 export interface SchemaColumnHeaderProps {
     columnKeys: string[];
     columnWidths: number[];
     columnIndex: number;
     changeColumnKey: (index: number, newKey: string) => boolean;
+    addColumn: (index: number) => void;
+    removeColumn: (index: number) => void;
 }
 
 @observer
@@ -21,6 +24,23 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
         return (
             <div className="schema-column-header" style={{ width: this.props.columnWidths[this.props.columnIndex] }}>
                 <EditableView SetValue={(newKey: string) => this.props.changeColumnKey(this.props.columnIndex, newKey)} GetValue={() => this.fieldKey} contents={this.fieldKey} />
+
+                <div className="schema-header-menu">
+                    <div
+                        className="schema-header-button"
+                        onPointerDown={e => {
+                            this.props.addColumn(this.props.columnIndex + 1);
+                        }}>
+                        <FontAwesomeIcon icon="plus" />
+                    </div>
+                    <div
+                        className="schema-header-button"
+                        onPointerDown={e => {
+                            this.props.removeColumn(this.props.columnIndex);
+                        }}>
+                        <FontAwesomeIcon icon="trash" />
+                    </div>
+                </div>
             </div>
         );
     }
-- 
cgit v1.2.3-70-g09d2


From 330752fa253b61136b78ce7147e09e9d6004f833 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Thu, 18 Aug 2022 14:08:31 -0400
Subject: added external drop and column resize

---
 .../collectionSchema/CollectionSchemaView.scss     |  32 ++++++-
 .../collectionSchema/CollectionSchemaView.tsx      | 105 ++++++++++++++++++---
 .../collectionSchema/SchemaColumnHeader.tsx        |   8 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  |   6 +-
 4 files changed, 133 insertions(+), 18 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 83164a82a..1d0ab459d 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -11,11 +11,12 @@
         .schema-row {
             display: flex;
             flex-direction: row;
+            max-height: 70px;
+            overflow: auto;
 
             .schema-column-header,
             .schema-table-cell,
             .row-menu {
-                min-width: 50px;
                 border: 1px solid $medium-gray;
                 padding: 5px;
                 overflow: hidden;
@@ -31,6 +32,34 @@
                 flex-direction: row;
                 justify-content: space-between;
                 align-items: center;
+                padding: 0;
+
+                .schema-column-title {
+                    flex-grow: 2;
+                    margin: 5px;
+                }
+
+                .schema-header-menu {
+                    margin: 5px;
+                }
+
+                .schema-column-resizer {
+                    height: 100%;
+                    width: 3px;
+                    cursor: ew-resize;
+
+                    &:hover {
+                        background-color: $light-blue;
+                    }
+                }
+
+                .schema-column-resizer.right {
+                    align-self: flex-end;
+                }
+
+                .schema-column-resizer.left {
+                    align-self: flex-start;
+                }
             }
         }
 
@@ -41,6 +70,7 @@
                 display: flex;
                 flex-direction: row;
                 justify-content: center;
+                min-width: 50px;
             }
 
             .row-cells {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 4d96d5f7e..a09d2722c 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -2,25 +2,25 @@ import React = require('react');
 import { action, computed, observable, ObservableSet } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc, DocListCast } from '../../../../fields/Doc';
+import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
+import { RichTextField } from '../../../../fields/RichTextField';
 import { listSpec } from '../../../../fields/Schema';
 import { Cast, StrCast } from '../../../../fields/Types';
+import { ImageField } from '../../../../fields/URLField';
+import { emptyFunction, returnEmptyString, setupMoveUpEvents } from '../../../../Utils';
+import { Docs, DocUtils } from '../../../documents/Documents';
 import { DragManager } from '../../../util/DragManager';
-import { CollectionSubView } from '../CollectionSubView';
-import './CollectionSchemaView.scss';
-import { SchemaColumnHeader } from './SchemaColumnHeader';
-import { SchemaRowBox } from './SchemaRowBox';
 import { SelectionManager } from '../../../util/SelectionManager';
 import { undoBatch } from '../../../util/UndoManager';
-import { EditableView } from '../../EditableView';
-import { returnEmptyString } from '../../../../Utils';
-import { Docs, DocUtils } from '../../../documents/Documents';
-import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
 import { ContextMenu } from '../../ContextMenu';
 import { ContextMenuProps } from '../../ContextMenuItem';
-import { Id } from '../../../../fields/FieldSymbols';
-import { RichTextField } from '../../../../fields/RichTextField';
-import { ImageField } from '../../../../fields/URLField';
+import { EditableView } from '../../EditableView';
+import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
+import { CollectionSubView } from '../CollectionSubView';
+import './CollectionSchemaView.scss';
+import { SchemaColumnHeader } from './SchemaColumnHeader';
+import { SchemaRowBox } from './SchemaRowBox';
 
 export enum ColumnType {
     Number,
@@ -38,16 +38,18 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _lastSelectedRow: number | undefined;
     private _selectedDocSortedArray: Doc[] = [];
     private _closestDropIndex: number = 0;
+    private _minColWidth: number = 120;
 
     @observable _rowMenuWidth: number = 100;
     @observable _selectedDocs: ObservableSet = new ObservableSet<SchemaRowBox>();
     @observable _isDragging: boolean = false;
+    @observable _displayColumnWidths: number[] | undefined;
 
     @computed get columnKeys() {
         return Cast(this.layoutDoc.columnKeys, listSpec('string'), defaultColumnKeys);
     }
 
-    @computed get columnWidths() {
+    @computed get storedColumnWidths() {
         return Cast(
             this.layoutDoc.columnWidths,
             listSpec('number'),
@@ -55,6 +57,10 @@ export class CollectionSchemaView extends CollectionSubView() {
         );
     }
 
+    @computed get displayColumnWidths() {
+        return this._displayColumnWidths ?? this.storedColumnWidths;
+    }
+
     @undoBatch
     @action
     changeColumnKey = (index: number, newKey: string) => {
@@ -80,6 +86,51 @@ export class CollectionSchemaView extends CollectionSubView() {
         this.layoutDoc.columnKeys = new List<string>(currKeys);
     };
 
+    @action
+    startResize = (e: any, index: number, left: boolean) => {
+        this._displayColumnWidths = this.storedColumnWidths;
+        setupMoveUpEvents(this, e, (e, delta) => this.resizeColumn(e, index, left), this.finishResize, emptyFunction);
+    };
+
+    @action
+    resizeColumn = (e: PointerEvent, index: number, left: boolean) => {
+        if (this._displayColumnWidths) {
+            let shrinking;
+            let growing;
+
+            let change = e.movementX;
+
+            if (left && index !== 0) {
+                growing = change < 0 ? index : index - 1;
+                shrinking = change < 0 ? index - 1 : index;
+            } else if (!left && index !== this.columnKeys.length - 1) {
+                growing = change > 0 ? index : index + 1;
+                shrinking = change > 0 ? index + 1 : index;
+            }
+
+            if (shrinking === undefined || growing === undefined) return true;
+
+            change = Math.abs(change);
+            if (this._displayColumnWidths[shrinking] - change < this._minColWidth) {
+                change = this._displayColumnWidths[shrinking] - this._minColWidth;
+            }
+
+            this._displayColumnWidths[shrinking] -= change;
+            this._displayColumnWidths[growing] += change;
+
+            return false;
+        }
+        return true;
+    };
+
+    // @undoBatch
+    @action
+    finishResize = () => {
+        console.log('finished');
+        this.layoutDoc.columnWidths = new List<number>(this._displayColumnWidths);
+        this._displayColumnWidths = undefined;
+    };
+
     @action
     selectRow = (e: React.PointerEvent, doc: Doc, index: number) => {
         const ctrl = e.ctrlKey || e.metaKey;
@@ -135,6 +186,21 @@ export class CollectionSchemaView extends CollectionSubView() {
         return false;
     };
 
+    @action
+    onExternalDrop = async (e: React.DragEvent): Promise<void> => {
+        console.log('hello');
+        super.onExternalDrop(
+            e,
+            {},
+            undoBatch(
+                action(docus => {
+                    this._isDragging = false;
+                    docus.map((doc: Doc) => this.addDocument(doc));
+                })
+            )
+        );
+    };
+
     @action
     startDrag = (e: React.PointerEvent, doc: Doc) => {
         if (!this._selectedDocs.has(doc)) {
@@ -251,11 +317,20 @@ export class CollectionSchemaView extends CollectionSubView() {
                     this._ref = ele;
                     this.createDashEventsTarget(ele);
                 }}
-                onPointerDown={() => this._selectedDocs.clear()}>
+                onPointerDown={() => this._selectedDocs.clear()}
+                onDrop={this.onExternalDrop.bind(this)}>
                 <div className="schema-table">
                     <div className="schema-header-row">
                         {this.columnKeys.map((key, index) => (
-                            <SchemaColumnHeader columnIndex={index} columnKeys={this.columnKeys} columnWidths={this.columnWidths} changeColumnKey={this.changeColumnKey} addColumn={this.addColumn} removeColumn={this.removeColumn} />
+                            <SchemaColumnHeader
+                                columnIndex={index}
+                                columnKeys={this.columnKeys}
+                                columnWidths={this.displayColumnWidths}
+                                changeColumnKey={this.changeColumnKey}
+                                addColumn={this.addColumn}
+                                removeColumn={this.removeColumn}
+                                resizeColumn={this.startResize}
+                            />
                         ))}
                     </div>
                     <div className="schema-table-content">
@@ -267,7 +342,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 ContainingCollectionView={this.props.CollectionView}
                                 rowIndex={index}
                                 columnKeys={this.columnKeys}
-                                columnWidths={this.columnWidths}
+                                columnWidths={this.displayColumnWidths}
                                 rowMenuWidth={this._rowMenuWidth}
                                 selectedRows={this._selectedDocs}
                                 selectRow={this.selectRow}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index f93a3d13d..bee76bb24 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -12,6 +12,7 @@ export interface SchemaColumnHeaderProps {
     changeColumnKey: (index: number, newKey: string) => boolean;
     addColumn: (index: number) => void;
     removeColumn: (index: number) => void;
+    resizeColumn: (e: any, index: number, left: boolean) => void;
 }
 
 @observer
@@ -23,7 +24,10 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
     render() {
         return (
             <div className="schema-column-header" style={{ width: this.props.columnWidths[this.props.columnIndex] }}>
-                <EditableView SetValue={(newKey: string) => this.props.changeColumnKey(this.props.columnIndex, newKey)} GetValue={() => this.fieldKey} contents={this.fieldKey} />
+                <div className="schema-column-resizer left" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex, true)}></div>
+                <div className="schema-column-title">
+                    <EditableView SetValue={(newKey: string) => this.props.changeColumnKey(this.props.columnIndex, newKey)} GetValue={() => this.fieldKey} contents={this.fieldKey} />
+                </div>
 
                 <div className="schema-header-menu">
                     <div
@@ -41,6 +45,8 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
                         <FontAwesomeIcon icon="trash" />
                     </div>
                 </div>
+
+                <div className="schema-column-resizer right" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex, false)}></div>
             </div>
         );
     }
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 3d1fa0ee2..661056553 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -6,7 +6,7 @@ import { Doc } from '../../../../fields/Doc';
 import { undoBatch } from '../../../util/UndoManager';
 import { ViewBoxBaseComponent } from '../../DocComponent';
 import { Colors } from '../../global/globalEnums';
-import { FieldViewProps } from '../../nodes/FieldView';
+import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
 import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
@@ -26,6 +26,10 @@ export interface SchemaRowBoxProps extends FieldViewProps {
 
 @observer
 export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
+    public static LayoutString(fieldKey: string) {
+        return FieldView.LayoutString(SchemaRowBox, fieldKey);
+    }
+
     private _ref: HTMLDivElement | null = null;
 
     isSelected = () => this.props.selectedRows.has(this.props.Document);
-- 
cgit v1.2.3-70-g09d2


From 213a92ba3aa39d144754029fde32b9d69b0f51cf Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 7 Nov 2022 12:57:44 -0500
Subject: basic key selection menu created

---
 .../collectionSchema/CollectionSchemaView.scss     |   8 ++
 .../collectionSchema/CollectionSchemaView.tsx      | 150 +++++++++++++++------
 .../collectionSchema/SchemaColumnHeader.tsx        | 105 +++++++++++++--
 .../collections/collectionSchema/SchemaRowBox.tsx  |  12 +-
 4 files changed, 223 insertions(+), 52 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 4d7e8c39f..0631cd21d 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -44,6 +44,13 @@
                 .schema-column-resizer.left {
                     align-self: flex-start;
                 }
+
+                .schema-column-menu {
+                    background: $light-gray;
+                    width: inherit;
+                    position: absolute;
+                    top: 35px;
+                }
             }
         }
 
@@ -72,6 +79,7 @@
 
 .schema-row {
     justify-content: flex-end;
+    background: white;
 
     .row-menu {
         display: flex;
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 84a69d4b9..7516b95b8 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,7 +1,7 @@
 import React = require('react');
-import { action, computed, observable, ObservableMap, ObservableSet } from 'mobx';
+import { action, computed, observable, ObservableMap, ObservableSet, untracked } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, DocListCast } from '../../../../fields/Doc';
+import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { RichTextField } from '../../../../fields/RichTextField';
@@ -41,10 +41,26 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _minColWidth: number = 120;
 
     @observable _rowMenuWidth: number = 100;
-    @observable _selectedDocs: ObservableMap = new ObservableMap<SchemaRowBox, HTMLDivElement>();
+    @observable _selectedDocs: ObservableSet = new ObservableSet<Doc>();
+    @observable _rowEles: ObservableMap = new ObservableMap<Doc, HTMLDivElement>();
     @observable _isDragging: boolean = false;
     @observable _displayColumnWidths: number[] | undefined;
 
+    get documentKeys() {
+        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)))));
+
+        // this.columns.forEach(key => (keys[key.heading] = true));
+        return Array.from(Object.keys(keys));
+    }
+
     @computed get columnKeys() {
         return Cast(this.layoutDoc.columnKeys, listSpec('string'), defaultColumnKeys);
     }
@@ -64,6 +80,10 @@ export class CollectionSchemaView extends CollectionSubView() {
     @undoBatch
     @action
     changeColumnKey = (index: number, newKey: string) => {
+        if (!this.documentKeys.includes(newKey)) {
+            this.addNewKey(newKey);
+        }
+
         let currKeys = this.columnKeys;
         currKeys[index] = newKey;
         this.layoutDoc.columnKeys = new List<string>(currKeys);
@@ -72,10 +92,10 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @undoBatch
     @action
-    addColumn = (index: number) => {
-        let currKeys = this.columnKeys;
-        currKeys.splice(index, 0, 'title');
-        this.layoutDoc.columnKeys = new List<string>(currKeys);
+    addColumn = (index: number, key: string) => {
+        if (!this.documentKeys.includes(key)) {
+            this.addNewKey(key);
+        }
 
         const newColWidth = this._minColWidth;
         let currWidths = this.storedColumnWidths;
@@ -83,17 +103,22 @@ export class CollectionSchemaView extends CollectionSubView() {
             const proportion = w / (this.props.PanelWidth() - this._rowMenuWidth);
             return proportion * (this.props.PanelWidth() - this._rowMenuWidth - newColWidth);
         });
-        currWidths.splice(index, 0, newColWidth);
+        currWidths.splice(index + 1, 0, newColWidth);
         this.layoutDoc.columnWidths = new List<number>(currWidths);
+
+        let currKeys = this.columnKeys;
+        currKeys.splice(index + 1, 0, key);
+        this.layoutDoc.columnKeys = new List<string>(currKeys);
+    };
+
+    @action
+    addNewKey = (key: string) => {
+        this.childDocs.forEach(doc => (doc[key] = key + ' default val'));
     };
 
     @undoBatch
     @action
     removeColumn = (index: number) => {
-        let currKeys = this.columnKeys;
-        currKeys.splice(index, 1);
-        this.layoutDoc.columnKeys = new List<string>(currKeys);
-
         let currWidths = this.storedColumnWidths;
         const removedColWidth = currWidths[index];
         currWidths = currWidths.map(w => {
@@ -102,6 +127,10 @@ export class CollectionSchemaView extends CollectionSubView() {
         });
         currWidths.splice(index, 1);
         this.layoutDoc.columnWidths = new List<number>(currWidths);
+
+        let currKeys = this.columnKeys;
+        currKeys.splice(index, 1);
+        this.layoutDoc.columnKeys = new List<string>(currKeys);
     };
 
     @action
@@ -143,11 +172,55 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     finishResize = () => {
-        console.log('finished');
         this.layoutDoc.columnWidths = new List<number>(this._displayColumnWidths);
         this._displayColumnWidths = undefined;
     };
 
+    @undoBatch
+    @action
+    swapColumns = (index1: number, index2: number) => {
+        console.log(index1, index2);
+        const tempKey = this.columnKeys[index1];
+        const tempWidth = this.storedColumnWidths[index1];
+
+        let currKeys = this.columnKeys;
+        currKeys[index1] = currKeys[index2];
+        currKeys[index2] = tempKey;
+        this.layoutDoc.columnKeys = new List<string>(currKeys);
+
+        let currWidths = this.storedColumnWidths;
+        currWidths[index1] = currWidths[index2];
+        currWidths[index2] = tempWidth;
+        this.layoutDoc.columnWidths = new List<number>(currWidths);
+    };
+
+    @action
+    dragColumn = (e: any, index: number) => {
+        console.log(index);
+        e.stopPropagation();
+        e.preventDefault();
+        const rect = e.target.getBoundingClientRect();
+        if (e.clientX < rect.x) {
+            console.log('left', e.clientX, rect.x);
+            if (index < 1) return true;
+            this.swapColumns(index - 1, index);
+            return true;
+        }
+        if (e.clientX > rect.x + rect.width) {
+            console.log('right', e.clientX, rect.x + rect.width);
+            if (index === this.columnKeys.length) return true;
+            console.log(index);
+            this.swapColumns(index, index + 1);
+            return true;
+        }
+        return false;
+    };
+
+    @action
+    addRowRef = (doc: Doc, ref: HTMLDivElement) => {
+        this._rowEles.set(doc, ref);
+    };
+
     @action
     selectRow = (e: React.PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => {
         const ctrl = e.ctrlKey || e.metaKey;
@@ -157,19 +230,19 @@ export class CollectionSchemaView extends CollectionSubView() {
             const endRow = Math.max(this._lastSelectedRow, index);
             for (let i = startRow; i <= endRow; i++) {
                 const currDoc: Doc = this.childDocs[i];
-                if (!this._selectedDocs.has(currDoc)) this._selectedDocs.set(currDoc, ref);
+                if (!this._selectedDocs.has(currDoc)) this._selectedDocs.add(currDoc);
             }
             this._lastSelectedRow = endRow;
         } else if (ctrl) {
             if (!this._selectedDocs.has(doc)) {
-                this._selectedDocs.set(doc, ref);
+                this._selectedDocs.add(doc);
                 this._lastSelectedRow = index;
             } else {
                 this._selectedDocs.delete(doc);
             }
         } else {
             this._selectedDocs.clear();
-            this._selectedDocs.set(doc, ref);
+            this._selectedDocs.add(doc);
             this._lastSelectedRow = index;
         }
 
@@ -205,7 +278,6 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     onExternalDrop = async (e: React.DragEvent): Promise<void> => {
-        console.log('hello');
         super.onExternalDrop(
             e,
             {},
@@ -222,7 +294,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     startDrag = (e: React.PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => {
         if (!this._selectedDocs.has(doc)) {
             this._selectedDocs.clear();
-            this._selectedDocs.set(doc, ref);
+            this._selectedDocs.add(doc);
             this._lastSelectedRow = index;
             SelectionManager.SelectSchemaViewDoc(doc);
         }
@@ -230,14 +302,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._selectedDocSortedArray = this.sortedSelectedDocs();
         const dragData = new DragManager.DocumentDragData(this._selectedDocSortedArray, 'move');
         dragData.moveDocument = this.props.moveDocument;
-        const dragItem: HTMLElement[] = Array.from(this._selectedDocs.values());
-        // const dragDiv = document.createElement('div');
-        // dragDiv.className = 'presItem-multiDrag';
-        // dragDiv.innerText = 'Move ' + this._selectedDocs.size + '  row' + (this._selectedDocs.size > 1 ? 's' : '');
-        // dragDiv.style.position = 'absolute';
-        // dragDiv.style.top = e.clientY + 'px';
-        // dragDiv.style.left = e.clientX - 50 + 'px';
-        // dragItem.push(dragDiv);
+        const dragItem: HTMLElement[] = Array.from(this._selectedDocs.values()).map((doc: Doc) => this._rowEles.get(doc));
 
         DragManager.StartDocumentDrag(
             dragItem.map(ele => ele),
@@ -334,21 +399,27 @@ export class CollectionSchemaView extends CollectionSubView() {
                     this._ref = ele;
                     this.createDashEventsTarget(ele);
                 }}
-                onPointerDown={() => this._selectedDocs.clear()}
+                onPointerDown={action(() => {
+                    this._selectedDocs.clear();
+                })}
                 onDrop={this.onExternalDrop.bind(this)}>
                 <div className="schema-table">
                     <div className="schema-header-row">
-                        {this.columnKeys.map((key, index) => (
-                            <SchemaColumnHeader
-                                columnIndex={index}
-                                columnKeys={this.columnKeys}
-                                columnWidths={this.displayColumnWidths}
-                                changeColumnKey={this.changeColumnKey}
-                                addColumn={this.addColumn}
-                                removeColumn={this.removeColumn}
-                                resizeColumn={this.startResize}
-                            />
-                        ))}
+                        {this.columnKeys.map((key, index) => {
+                            return (
+                                <SchemaColumnHeader
+                                    columnIndex={index}
+                                    columnKeys={this.columnKeys}
+                                    columnWidths={this.displayColumnWidths}
+                                    possibleKeys={this.documentKeys}
+                                    changeColumnKey={this.changeColumnKey}
+                                    addColumn={this.addColumn}
+                                    removeColumn={this.removeColumn}
+                                    resizeColumn={this.startResize}
+                                    dragColumn={this.dragColumn}
+                                />
+                            );
+                        })}
                     </div>
                     <div className="schema-table-content">
                         {this.childDocs.map((doc: Doc, index: number) => (
@@ -361,11 +432,12 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 columnKeys={this.columnKeys}
                                 columnWidths={this.displayColumnWidths}
                                 rowMenuWidth={this._rowMenuWidth}
-                                selectedRows={this._selectedDocs}
+                                selectedDocs={this._selectedDocs}
                                 selectRow={this.selectRow}
                                 startDrag={this.startDrag}
                                 dragging={this._isDragging}
                                 dropIndex={this.setDropIndex}
+                                addRowRef={this.addRowRef}
                             />
                         ))}
                     </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index bee76bb24..a6140bafd 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -1,39 +1,124 @@
 import React = require('react');
-import { computed } from 'mobx';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
-import { EditableView } from '../../EditableView';
+import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
 import './CollectionSchemaView.scss';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 
 export interface SchemaColumnHeaderProps {
     columnKeys: string[];
     columnWidths: number[];
     columnIndex: number;
+    possibleKeys: string[];
     changeColumnKey: (index: number, newKey: string) => boolean;
-    addColumn: (index: number) => void;
+    addColumn: (index: number, key: string) => void;
     removeColumn: (index: number) => void;
     resizeColumn: (e: any, index: number, left: boolean) => void;
+    dragColumn: (e: any, index: number) => boolean;
 }
 
 @observer
 export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps> {
+    @observable _menuVisible: boolean = false;
+    @observable _menuValue: string = '';
+    @observable _menuOptions: string[] = [];
+    private _makeNewColumn = false;
+
     @computed get fieldKey() {
         return this.props.columnKeys[this.props.columnIndex];
     }
 
+    @computed get renderColumnMenu() {
+        return (
+            <div className="schema-column-menu">
+                <input type="text" value={this._menuValue} onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
+                {this._menuOptions.map(key => (
+                    <div
+                        onPointerDown={e => {
+                            e.stopPropagation();
+                            this.setKey(key);
+                        }}>
+                        {key}
+                    </div>
+                ))}
+                <div
+                    onPointerDown={e => {
+                        e.stopPropagation();
+                        this.setKey(this._menuValue);
+                    }}>
+                    + new field
+                </div>
+            </div>
+        );
+    }
+
+    onSearchKeyDown = (e: React.KeyboardEvent) => {
+        switch (e.key) {
+            case 'Enter':
+                this.setKey(this._menuOptions.length > 0 ? this._menuOptions[0] : this._menuValue);
+                break;
+            case 'Escape':
+                this.toggleColumnMenu();
+                break;
+        }
+    };
+
+    @action
+    setKey = (key: string) => {
+        if (this._makeNewColumn) {
+            this.props.addColumn(this.props.columnIndex, key);
+        } else {
+            this.props.changeColumnKey(this.props.columnIndex, key);
+        }
+        this.toggleColumnMenu();
+    };
+
+    @action
+    updateKeySearch = (e: React.ChangeEvent<HTMLInputElement>) => {
+        this._menuValue = e.target.value;
+        this._menuOptions = this.props.possibleKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
+    };
+
+    @action
+    onPointerDown = (e: React.PointerEvent) => {
+        e.stopPropagation();
+
+        setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction);
+    };
+
+    @action
+    toggleColumnMenu = (newCol?: boolean) => {
+        this._makeNewColumn = false;
+        if (this._menuVisible) {
+            this._menuVisible = false;
+        } else {
+            this._menuVisible = true;
+            this._menuValue = this.fieldKey;
+            this._menuOptions = this.props.possibleKeys;
+            if (newCol) {
+                this._makeNewColumn = true;
+            }
+        }
+    };
+
     render() {
         return (
-            <div className="schema-column-header" style={{ width: this.props.columnWidths[this.props.columnIndex] }}>
+            <div className="schema-column-header" style={{ width: this.props.columnWidths[this.props.columnIndex] }} onPointerDown={this.onPointerDown}>
                 <div className="schema-column-resizer left" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex, true)}></div>
-                <div className="schema-column-title">
-                    <EditableView SetValue={(newKey: string) => this.props.changeColumnKey(this.props.columnIndex, newKey)} GetValue={() => this.fieldKey} contents={this.fieldKey} />
-                </div>
+                <div className="schema-column-title">{this.fieldKey}</div>
 
                 <div className="schema-header-menu">
                     <div
                         className="schema-header-button"
                         onPointerDown={e => {
-                            this.props.addColumn(this.props.columnIndex + 1);
+                            this.toggleColumnMenu();
+                        }}>
+                        <FontAwesomeIcon icon="pencil-alt" />
+                    </div>
+                    <div
+                        className="schema-header-button"
+                        onPointerDown={e => {
+                            this.toggleColumnMenu(true);
                         }}>
                         <FontAwesomeIcon icon="plus" />
                     </div>
@@ -47,6 +132,8 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
                 </div>
 
                 <div className="schema-column-resizer right" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex, false)}></div>
+
+                {this._menuVisible && this.renderColumnMenu}
             </div>
         );
     }
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 66cc3a47a..bfce61952 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -17,11 +17,12 @@ export interface SchemaRowBoxProps extends FieldViewProps {
     columnKeys: string[];
     columnWidths: number[];
     rowMenuWidth: number;
-    selectedRows: ObservableMap<Doc, HTMLDivElement>;
+    selectedDocs: ObservableSet<Doc>;
     selectRow: (e: any, doc: Doc, ref: HTMLDivElement, index: number) => void;
     startDrag: (e: any, doc: Doc, ref: HTMLDivElement, index: number) => boolean;
     dragging: boolean;
     dropIndex: (index: number) => void;
+    addRowRef: (doc: Doc, ref: HTMLDivElement) => void;
 }
 
 @observer
@@ -32,7 +33,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
 
     private _ref: HTMLDivElement | null = null;
 
-    isSelected = () => this.props.selectedRows.has(this.props.Document);
+    isSelected = () => this.props.selectedDocs.has(this.props.Document);
     bounds = () => this._ref?.getBoundingClientRect();
 
     @action
@@ -58,7 +59,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
         if (!this.props.dragging) return;
         let dragIsRow: boolean = true;
         DragManager.docsBeingDragged.forEach(doc => {
-            dragIsRow = this.props.selectedRows.has(doc);
+            dragIsRow = this.props.selectedDocs.has(doc);
         });
         if (this._ref && dragIsRow) {
             const rect = this._ref.getBoundingClientRect();
@@ -93,7 +94,10 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                 onPointerDown={this.onRowPointerDown}
                 onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
-                ref={(row: HTMLDivElement | null) => (this._ref = row)}>
+                ref={(row: HTMLDivElement | null) => {
+                    row && this.props.addRowRef(this.props.Document, row);
+                    this._ref = row;
+                }}>
                 <div className="row-menu" style={{ width: this.props.rowMenuWidth }}>
                     <div
                         className="schema-row-button"
-- 
cgit v1.2.3-70-g09d2


From c3d7e526247dd6225af5146e93a0001d56a84c29 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 14 Nov 2022 10:22:29 -0500
Subject: added menu for creating new keys

---
 .../collectionSchema/CollectionSchemaView.scss     |   2 +
 .../collectionSchema/CollectionSchemaView.tsx      |  16 ++--
 .../collectionSchema/SchemaColumnHeader.tsx        | 103 +++++++++++++++++----
 3 files changed, 93 insertions(+), 28 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 0631cd21d..696bfd67c 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -50,6 +50,8 @@
                     width: inherit;
                     position: absolute;
                     top: 35px;
+                    min-width: 200px;
+                    padding: 10px;
                 }
             }
         }
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 7516b95b8..0466ce343 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -79,26 +79,25 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @undoBatch
     @action
-    changeColumnKey = (index: number, newKey: string) => {
+    changeColumnKey = (index: number, newKey: string, defaultVal?: any) => {
         if (!this.documentKeys.includes(newKey)) {
-            this.addNewKey(newKey);
+            this.addNewKey(newKey, defaultVal);
         }
 
         let currKeys = this.columnKeys;
         currKeys[index] = newKey;
         this.layoutDoc.columnKeys = new List<string>(currKeys);
-        return true;
     };
 
     @undoBatch
     @action
-    addColumn = (index: number, key: string) => {
+    addColumn = (index: number, key: string, defaultVal?: any) => {
         if (!this.documentKeys.includes(key)) {
-            this.addNewKey(key);
+            this.addNewKey(key, defaultVal);
         }
 
-        const newColWidth = this._minColWidth;
         let currWidths = this.storedColumnWidths;
+        const newColWidth = this.props.PanelWidth() / (currWidths.length + 1);
         currWidths = currWidths.map(w => {
             const proportion = w / (this.props.PanelWidth() - this._rowMenuWidth);
             return proportion * (this.props.PanelWidth() - this._rowMenuWidth - newColWidth);
@@ -112,8 +111,9 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     @action
-    addNewKey = (key: string) => {
-        this.childDocs.forEach(doc => (doc[key] = key + ' default val'));
+    addNewKey = (key: string, defaultVal: any) => {
+        console.log(defaultVal);
+        this.childDocs.forEach(doc => (doc[key] = defaultVal));
     };
 
     @undoBatch
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index a6140bafd..cdae79d0c 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -4,14 +4,15 @@ import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
 import './CollectionSchemaView.scss';
+import { ColumnType } from './CollectionSchemaView';
 
 export interface SchemaColumnHeaderProps {
     columnKeys: string[];
     columnWidths: number[];
     columnIndex: number;
     possibleKeys: string[];
-    changeColumnKey: (index: number, newKey: string) => boolean;
-    addColumn: (index: number, key: string) => void;
+    changeColumnKey: (index: number, newKey: string, defaultVal?: any) => void;
+    addColumn: (index: number, key: string, defaultVal?: any) => void;
     removeColumn: (index: number) => void;
     resizeColumn: (e: any, index: number, left: boolean) => void;
     dragColumn: (e: any, index: number) => boolean;
@@ -20,6 +21,9 @@ export interface SchemaColumnHeaderProps {
 @observer
 export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps> {
     @observable _menuVisible: boolean = false;
+    @observable _makeNewField: boolean = false;
+    @observable _newFieldType: ColumnType = ColumnType.Number;
+    @observable _newFieldDefault: any = 0;
     @observable _menuValue: string = '';
     @observable _menuOptions: string[] = [];
     private _makeNewColumn = false;
@@ -28,26 +32,85 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
         return this.props.columnKeys[this.props.columnIndex];
     }
 
+    @computed get fieldDefaultInput() {
+        switch (this._newFieldType) {
+            case ColumnType.Number:
+                return <input type="number" name="" id="" value={this._newFieldDefault ?? 0} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />;
+            case ColumnType.Boolean:
+                return <input type="checkbox" name="" id="" value={this._newFieldDefault ?? false} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />;
+            case ColumnType.String:
+                return <input type="text" name="" id="" value={this._newFieldDefault ?? ''} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />;
+        }
+    }
+
     @computed get renderColumnMenu() {
         return (
             <div className="schema-column-menu">
                 <input type="text" value={this._menuValue} onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
-                {this._menuOptions.map(key => (
-                    <div
-                        onPointerDown={e => {
-                            e.stopPropagation();
-                            this.setKey(key);
-                        }}>
-                        {key}
+                {this._makeNewField ? (
+                    <div className="schema-new-key-options">
+                        <input
+                            type="radio"
+                            name="newFieldType"
+                            id=""
+                            checked={this._newFieldType == ColumnType.Number}
+                            onChange={action(() => {
+                                this._newFieldType = ColumnType.Number;
+                                this._newFieldDefault = 0;
+                            })}
+                        />{' '}
+                        math
+                        <input
+                            type="radio"
+                            name="newFieldType"
+                            id=""
+                            checked={this._newFieldType == ColumnType.Boolean}
+                            onChange={action(() => {
+                                this._newFieldType = ColumnType.Boolean;
+                                this._newFieldDefault = false;
+                            })}
+                        />{' '}
+                        boolean
+                        <input
+                            type="radio"
+                            name="newFieldType"
+                            id=""
+                            checked={this._newFieldType == ColumnType.String}
+                            onChange={action(() => {
+                                this._newFieldType = ColumnType.String;
+                                this._newFieldDefault = '';
+                            })}
+                        />{' '}
+                        string
+                        {this.fieldDefaultInput}
+                        <div
+                            onPointerDown={action(e => {
+                                this.setKey(this._menuValue, this._newFieldDefault);
+                                this._makeNewField = false;
+                            })}>
+                            done
+                        </div>
                     </div>
-                ))}
-                <div
-                    onPointerDown={e => {
-                        e.stopPropagation();
-                        this.setKey(this._menuValue);
-                    }}>
-                    + new field
-                </div>
+                ) : (
+                    <div className="schema-key-search">
+                        <div
+                            onPointerDown={action(e => {
+                                e.stopPropagation();
+                                this._makeNewField = true;
+                            })}>
+                            + new field
+                        </div>
+                        {this._menuOptions.map(key => (
+                            <div
+                                onPointerDown={e => {
+                                    e.stopPropagation();
+                                    this.setKey(key);
+                                }}>
+                                {key}
+                            </div>
+                        ))}
+                    </div>
+                )}
             </div>
         );
     }
@@ -64,11 +127,11 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
     };
 
     @action
-    setKey = (key: string) => {
+    setKey = (key: string, defaultVal?: any) => {
         if (this._makeNewColumn) {
-            this.props.addColumn(this.props.columnIndex, key);
+            this.props.addColumn(this.props.columnIndex, key, defaultVal);
         } else {
-            this.props.changeColumnKey(this.props.columnIndex, key);
+            this.props.changeColumnKey(this.props.columnIndex, key, defaultVal);
         }
         this.toggleColumnMenu();
     };
-- 
cgit v1.2.3-70-g09d2


From a58e71a9eea2717151e1a8c73e27068b02256390 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 14 Nov 2022 11:19:48 -0500
Subject: cleanup

---
 .../collectionSchema/CollectionSchemaView.scss     |  56 ++++++++++-
 .../collectionSchema/CollectionSchemaView.tsx      |   2 +-
 .../collectionSchema/SchemaColumnHeader.tsx        | 107 ++++++++++++---------
 3 files changed, 118 insertions(+), 47 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 696bfd67c..99f49eb0e 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -51,7 +51,61 @@
                     position: absolute;
                     top: 35px;
                     min-width: 200px;
-                    padding: 10px;
+                    display: flex;
+                    flex-direction: column;
+                    align-items: flex-start;
+
+                    .schema-key-search-input {
+                        width: calc(100% - 20px);
+                        margin: 10px;
+                    }
+
+                    .schema-key-search-result {
+                        cursor: pointer;
+                        padding: 2px 10px;
+                        width: 100%;
+
+                        &:hover {
+                            background-color: $medium-gray;
+                        }
+                    }
+
+                    .schema-key-search,
+                    .schema-new-key-options {
+                        width: 100%;
+                        display: flex;
+                        flex-direction: column;
+                        align-items: flex-start;
+                    }
+
+                    .schema-key-list {
+                        width: 100%;
+                        max-height: 300px;
+                        overflow-y: auto;
+                    }
+
+                    .schema-key-type-option {
+                        margin: 2px 10px;
+
+                        input {
+                            margin-right: 5px;
+                        }
+                    }
+
+                    .schema-key-default-val {
+                        margin: 5px 10px;
+                    }
+
+                    .schema-column-menu-button {
+                        cursor: pointer;
+                        padding: 2px 5px;
+                        background: $medium-blue;
+                        border-radius: 9999px;
+                        color: $white;
+                        width: fit-content;
+                        margin: 5px;
+                        align-self: center;
+                    }
                 }
             }
         }
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 0466ce343..24008a21d 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -38,7 +38,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _lastSelectedRow: number | undefined;
     private _selectedDocSortedArray: Doc[] = [];
     private _closestDropIndex: number = 0;
-    private _minColWidth: number = 120;
+    private _minColWidth: number = 150;
 
     @observable _rowMenuWidth: number = 100;
     @observable _selectedDocs: ObservableSet = new ObservableSet<Doc>();
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index cdae79d0c..b9e25a473 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -37,7 +37,12 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
             case ColumnType.Number:
                 return <input type="number" name="" id="" value={this._newFieldDefault ?? 0} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />;
             case ColumnType.Boolean:
-                return <input type="checkbox" name="" id="" value={this._newFieldDefault ?? false} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />;
+                return (
+                    <>
+                        <input type="checkbox" name="" id="" value={this._newFieldDefault ?? false} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />
+                        {this._newFieldDefault ? 'true' : 'false'}
+                    </>
+                );
             case ColumnType.String:
                 return <input type="text" name="" id="" value={this._newFieldDefault ?? ''} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />;
         }
@@ -46,44 +51,51 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
     @computed get renderColumnMenu() {
         return (
             <div className="schema-column-menu">
-                <input type="text" value={this._menuValue} onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
+                <input className="schema-key-search-input" type="text" value={this._menuValue} onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
                 {this._makeNewField ? (
                     <div className="schema-new-key-options">
-                        <input
-                            type="radio"
-                            name="newFieldType"
-                            id=""
-                            checked={this._newFieldType == ColumnType.Number}
-                            onChange={action(() => {
-                                this._newFieldType = ColumnType.Number;
-                                this._newFieldDefault = 0;
-                            })}
-                        />{' '}
-                        math
-                        <input
-                            type="radio"
-                            name="newFieldType"
-                            id=""
-                            checked={this._newFieldType == ColumnType.Boolean}
-                            onChange={action(() => {
-                                this._newFieldType = ColumnType.Boolean;
-                                this._newFieldDefault = false;
-                            })}
-                        />{' '}
-                        boolean
-                        <input
-                            type="radio"
-                            name="newFieldType"
-                            id=""
-                            checked={this._newFieldType == ColumnType.String}
-                            onChange={action(() => {
-                                this._newFieldType = ColumnType.String;
-                                this._newFieldDefault = '';
-                            })}
-                        />{' '}
-                        string
-                        {this.fieldDefaultInput}
+                        <div className="schema-key-type-option">
+                            <input
+                                type="radio"
+                                name="newFieldType"
+                                id=""
+                                checked={this._newFieldType == ColumnType.Number}
+                                onChange={action(() => {
+                                    this._newFieldType = ColumnType.Number;
+                                    this._newFieldDefault = 0;
+                                })}
+                            />
+                            number
+                        </div>
+                        <div className="schema-key-type-option">
+                            <input
+                                type="radio"
+                                name="newFieldType"
+                                id=""
+                                checked={this._newFieldType == ColumnType.Boolean}
+                                onChange={action(() => {
+                                    this._newFieldType = ColumnType.Boolean;
+                                    this._newFieldDefault = false;
+                                })}
+                            />
+                            boolean
+                        </div>
+                        <div className="schema-key-type-option">
+                            <input
+                                type="radio"
+                                name="newFieldType"
+                                id=""
+                                checked={this._newFieldType == ColumnType.String}
+                                onChange={action(() => {
+                                    this._newFieldType = ColumnType.String;
+                                    this._newFieldDefault = '';
+                                })}
+                            />
+                            string
+                        </div>
+                        <div className="schema-key-default-val">value: {this.fieldDefaultInput}</div>
                         <div
+                            className="schema-column-menu-button"
                             onPointerDown={action(e => {
                                 this.setKey(this._menuValue, this._newFieldDefault);
                                 this._makeNewField = false;
@@ -94,21 +106,25 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
                 ) : (
                     <div className="schema-key-search">
                         <div
+                            className="schema-column-menu-button"
                             onPointerDown={action(e => {
                                 e.stopPropagation();
                                 this._makeNewField = true;
                             })}>
                             + new field
                         </div>
-                        {this._menuOptions.map(key => (
-                            <div
-                                onPointerDown={e => {
-                                    e.stopPropagation();
-                                    this.setKey(key);
-                                }}>
-                                {key}
-                            </div>
-                        ))}
+                        <div className="schema-key-list">
+                            {this._menuOptions.map(key => (
+                                <div
+                                    className="schema-key-search-result"
+                                    onPointerDown={e => {
+                                        e.stopPropagation();
+                                        this.setKey(key);
+                                    }}>
+                                    {key}
+                                </div>
+                            ))}
+                        </div>
                     </div>
                 )}
             </div>
@@ -158,6 +174,7 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
             this._menuVisible = true;
             this._menuValue = this.fieldKey;
             this._menuOptions = this.props.possibleKeys;
+            this._makeNewField = false;
             if (newCol) {
                 this._makeNewColumn = true;
             }
-- 
cgit v1.2.3-70-g09d2


From 73d3c63658c4bdf3268ea81a02eb96566869b855 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 21 Nov 2022 12:38:37 -0500
Subject: column deletion and new key menu fixes

---
 .../collectionSchema/CollectionSchemaView.scss     | 13 +++-
 .../collectionSchema/CollectionSchemaView.tsx      | 73 +++++++++++++---------
 .../collectionSchema/SchemaColumnHeader.tsx        | 31 +++++----
 .../collections/collectionSchema/SchemaRowBox.tsx  |  2 +-
 4 files changed, 74 insertions(+), 45 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 99f49eb0e..4fa5d80e2 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -78,6 +78,15 @@
                         align-items: flex-start;
                     }
 
+                    .schema-new-key-options {
+                        margin: 10px;
+                        .schema-key-warning {
+                            color: red;
+                            font-weight: normal;
+                            align-self: center;
+                        }
+                    }
+
                     .schema-key-list {
                         width: 100%;
                         max-height: 300px;
@@ -85,7 +94,7 @@
                     }
 
                     .schema-key-type-option {
-                        margin: 2px 10px;
+                        margin: 2px 0px;
 
                         input {
                             margin-right: 5px;
@@ -93,7 +102,7 @@
                     }
 
                     .schema-key-default-val {
-                        margin: 5px 10px;
+                        margin: 5px 0;
                     }
 
                     .schema-column-menu-button {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 24008a21d..f7c68c803 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,5 +1,5 @@
 import React = require('react');
-import { action, computed, observable, ObservableMap, ObservableSet, untracked } from 'mobx';
+import { action, computed, observable, ObservableMap, ObservableSet, trace, untracked } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
@@ -66,11 +66,22 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     @computed get storedColumnWidths() {
-        return Cast(
+        let widths = Cast(
             this.layoutDoc.columnWidths,
             listSpec('number'),
             this.columnKeys.map(() => (this.props.PanelWidth() - this._rowMenuWidth) / this.columnKeys.length)
         );
+
+        const totalWidth = widths.reduce((sum, width) => sum + width, 0);
+        if (totalWidth !== this.props.PanelWidth() - this._rowMenuWidth) {
+            widths = widths.map(w => {
+                const proportion = w / totalWidth;
+                return proportion * (this.props.PanelWidth() - this._rowMenuWidth);
+            });
+            // this.layoutDoc.columnWidths = new List<number>(widths);
+        }
+
+        return widths;
     }
 
     @computed get displayColumnWidths() {
@@ -84,7 +95,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             this.addNewKey(newKey, defaultVal);
         }
 
-        let currKeys = this.columnKeys;
+        let currKeys = [...this.columnKeys];
         currKeys[index] = newKey;
         this.layoutDoc.columnKeys = new List<string>(currKeys);
     };
@@ -96,7 +107,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             this.addNewKey(key, defaultVal);
         }
 
-        let currWidths = this.storedColumnWidths;
+        let currWidths = [...this.storedColumnWidths];
         const newColWidth = this.props.PanelWidth() / (currWidths.length + 1);
         currWidths = currWidths.map(w => {
             const proportion = w / (this.props.PanelWidth() - this._rowMenuWidth);
@@ -105,21 +116,21 @@ export class CollectionSchemaView extends CollectionSubView() {
         currWidths.splice(index + 1, 0, newColWidth);
         this.layoutDoc.columnWidths = new List<number>(currWidths);
 
-        let currKeys = this.columnKeys;
+        let currKeys = [...this.columnKeys];
         currKeys.splice(index + 1, 0, key);
         this.layoutDoc.columnKeys = new List<string>(currKeys);
     };
 
     @action
     addNewKey = (key: string, defaultVal: any) => {
-        console.log(defaultVal);
         this.childDocs.forEach(doc => (doc[key] = defaultVal));
     };
 
     @undoBatch
     @action
     removeColumn = (index: number) => {
-        let currWidths = this.storedColumnWidths;
+        if (this.columnKeys.length === 1) return;
+        let currWidths = [...this.storedColumnWidths];
         const removedColWidth = currWidths[index];
         currWidths = currWidths.map(w => {
             const proportion = w / (this.props.PanelWidth() - this._rowMenuWidth - removedColWidth);
@@ -128,9 +139,11 @@ export class CollectionSchemaView extends CollectionSubView() {
         currWidths.splice(index, 1);
         this.layoutDoc.columnWidths = new List<number>(currWidths);
 
-        let currKeys = this.columnKeys;
+        let currKeys = [...this.columnKeys];
         currKeys.splice(index, 1);
         this.layoutDoc.columnKeys = new List<string>(currKeys);
+        console.log([...this.storedColumnWidths]);
+        console.log([...this.columnKeys]);
     };
 
     @action
@@ -179,7 +192,6 @@ export class CollectionSchemaView extends CollectionSubView() {
     @undoBatch
     @action
     swapColumns = (index1: number, index2: number) => {
-        console.log(index1, index2);
         const tempKey = this.columnKeys[index1];
         const tempWidth = this.storedColumnWidths[index1];
 
@@ -194,27 +206,23 @@ export class CollectionSchemaView extends CollectionSubView() {
         this.layoutDoc.columnWidths = new List<number>(currWidths);
     };
 
-    @action
-    dragColumn = (e: any, index: number) => {
-        console.log(index);
-        e.stopPropagation();
-        e.preventDefault();
-        const rect = e.target.getBoundingClientRect();
-        if (e.clientX < rect.x) {
-            console.log('left', e.clientX, rect.x);
-            if (index < 1) return true;
-            this.swapColumns(index - 1, index);
-            return true;
-        }
-        if (e.clientX > rect.x + rect.width) {
-            console.log('right', e.clientX, rect.x + rect.width);
-            if (index === this.columnKeys.length) return true;
-            console.log(index);
-            this.swapColumns(index, index + 1);
-            return true;
-        }
-        return false;
-    };
+    // @action
+    // dragColumn = (e: any, index: number) => {
+    //     e.stopPropagation();
+    //     e.preventDefault();
+    //     const rect = e.target.getBoundingClientRect();
+    //     if (e.clientX < rect.x) {
+    //         if (index < 1) return true;
+    //         this.swapColumns(index - 1, index);
+    //         return true;
+    //     }
+    //     if (e.clientX > rect.x + rect.width) {
+    //         if (index === this.columnKeys.length) return true;
+    //         this.swapColumns(index, index + 1);
+    //         return true;
+    //     }
+    //     return false;
+    // };
 
     @action
     addRowRef = (doc: Doc, ref: HTMLDivElement) => {
@@ -405,9 +413,11 @@ export class CollectionSchemaView extends CollectionSubView() {
                 onDrop={this.onExternalDrop.bind(this)}>
                 <div className="schema-table">
                     <div className="schema-header-row">
+                        <div className="row-menu" style={{ width: this._rowMenuWidth }}></div>
                         {this.columnKeys.map((key, index) => {
                             return (
                                 <SchemaColumnHeader
+                                    key={index}
                                     columnIndex={index}
                                     columnKeys={this.columnKeys}
                                     columnWidths={this.displayColumnWidths}
@@ -416,7 +426,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                     addColumn={this.addColumn}
                                     removeColumn={this.removeColumn}
                                     resizeColumn={this.startResize}
-                                    dragColumn={this.dragColumn}
+                                    // dragColumn={this.dragColumn}
                                 />
                             );
                         })}
@@ -425,6 +435,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                         {this.childDocs.map((doc: Doc, index: number) => (
                             <SchemaRowBox
                                 {...this.props}
+                                key={index}
                                 Document={doc}
                                 ContainingCollectionDoc={this.props.CollectionView?.props.Document}
                                 ContainingCollectionView={this.props.CollectionView}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index b9e25a473..a6a5f66ab 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -15,7 +15,7 @@ export interface SchemaColumnHeaderProps {
     addColumn: (index: number, key: string, defaultVal?: any) => void;
     removeColumn: (index: number) => void;
     resizeColumn: (e: any, index: number, left: boolean) => void;
-    dragColumn: (e: any, index: number) => boolean;
+    // dragColumn: (e: any, index: number) => boolean;
 }
 
 @observer
@@ -24,6 +24,7 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
     @observable _makeNewField: boolean = false;
     @observable _newFieldType: ColumnType = ColumnType.Number;
     @observable _newFieldDefault: any = 0;
+    @observable _newFieldWarning: string = '';
     @observable _menuValue: string = '';
     @observable _menuOptions: string[] = [];
     private _makeNewColumn = false;
@@ -94,11 +95,17 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
                             string
                         </div>
                         <div className="schema-key-default-val">value: {this.fieldDefaultInput}</div>
+                        <div className="schema-key-warning">{this._newFieldWarning}</div>
                         <div
                             className="schema-column-menu-button"
                             onPointerDown={action(e => {
-                                this.setKey(this._menuValue, this._newFieldDefault);
-                                this._makeNewField = false;
+                                if (this.props.possibleKeys.includes(this._menuValue)) {
+                                    this._newFieldWarning = 'Field already exists';
+                                } else if (this._menuValue.length === 0) {
+                                    this._newFieldWarning = 'Field cannot be an empty string';
+                                } else {
+                                    this.setKey(this._menuValue, this._newFieldDefault);
+                                }
                             })}>
                             done
                         </div>
@@ -134,7 +141,7 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
     onSearchKeyDown = (e: React.KeyboardEvent) => {
         switch (e.key) {
             case 'Enter':
-                this.setKey(this._menuOptions.length > 0 ? this._menuOptions[0] : this._menuValue);
+                this.setKey(this._menuOptions.length > 0 && this._menuValue.length > 0 ? this._menuOptions[0] : this._menuValue);
                 break;
             case 'Escape':
                 this.toggleColumnMenu();
@@ -158,12 +165,12 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
         this._menuOptions = this.props.possibleKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
     };
 
-    @action
-    onPointerDown = (e: React.PointerEvent) => {
-        e.stopPropagation();
+    // @action
+    // onPointerDown = (e: React.PointerEvent) => {
+    //     e.stopPropagation();
 
-        setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction);
-    };
+    //     setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction);
+    // };
 
     @action
     toggleColumnMenu = (newCol?: boolean) => {
@@ -172,9 +179,11 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
             this._menuVisible = false;
         } else {
             this._menuVisible = true;
-            this._menuValue = this.fieldKey;
+            this._menuValue = '';
             this._menuOptions = this.props.possibleKeys;
             this._makeNewField = false;
+            this._newFieldWarning = '';
+            this._makeNewField = false;
             if (newCol) {
                 this._makeNewColumn = true;
             }
@@ -183,7 +192,7 @@ 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}>
+            <div className="schema-column-header" style={{ width: this.props.columnWidths[this.props.columnIndex] }}>
                 <div className="schema-column-resizer left" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex, true)}></div>
                 <div className="schema-column-title">{this.fieldKey}</div>
 
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index bfce61952..5c1f32565 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -118,7 +118,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                 </div>
                 <div className="row-cells">
                     {this.props.columnKeys.map((key, index) => (
-                        <SchemaTableCell Document={this.props.Document} fieldKey={key} columnWidth={this.props.columnWidths[index]} />
+                        <SchemaTableCell key={key} Document={this.props.Document} fieldKey={key} columnWidth={this.props.columnWidths[index]} />
                     ))}
                 </div>
             </div>
-- 
cgit v1.2.3-70-g09d2


From 6c58ca9d473103624be82c6f2da90f22bafd7b98 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Sat, 28 Jan 2023 23:27:17 -0500
Subject: version without schemarow as documentview

---
 src/client/documents/DocumentTypes.ts              |  1 -
 src/client/documents/Documents.ts                  | 11 ---
 .../collectionSchema/CollectionSchemaView.scss     |  6 --
 .../collectionSchema/CollectionSchemaView.tsx      | 94 ++++++----------------
 .../collectionSchema/SchemaColumnHeader.tsx        |  2 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  | 88 +++++++-------------
 src/client/views/nodes/DocumentContentsView.tsx    |  2 -
 7 files changed, 53 insertions(+), 151 deletions(-)

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

diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index b910b26b0..d99cd2dac 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -40,7 +40,6 @@ export enum DocumentType {
     SEARCHITEM = 'searchitem',
     COMPARISON = 'comparison',
     GROUP = 'group',
-    SCHEMAROW = 'schemarow',
 
     LINKDB = 'linkdb', // database of links  ??? why do we have this
     SCRIPTDB = 'scriptdb', // database of scripts
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index f6104d655..7de1221cc 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -26,7 +26,6 @@ import { ScriptingGlobals } from '../util/ScriptingGlobals';
 import { undoBatch, UndoManager } from '../util/UndoManager';
 import { CollectionDockingView } from '../views/collections/CollectionDockingView';
 import { DimUnit } from '../views/collections/collectionMulticolumn/CollectionMulticolumnView';
-import { SchemaRowBox } from '../views/collections/collectionSchema/SchemaRowBox';
 import { CollectionView } from '../views/collections/CollectionView';
 import { ContextMenu } from '../views/ContextMenu';
 import { ContextMenuProps } from '../views/ContextMenuItem';
@@ -650,12 +649,6 @@ export namespace Docs {
                     options: { _fitWidth: true, nativeDimModifiable: true, links: '@links(self)' },
                 },
             ],
-            [
-                DocumentType.SCHEMAROW,
-                {
-                    layout: { view: SchemaRowBox, dataField: defaultDataKey },
-                },
-            ],
             [
                 DocumentType.LOADING,
                 {
@@ -1148,10 +1141,6 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.DATAVIZ), new CsvField(url), { title: 'Data Viz', ...options });
         }
 
-        export function SchemaRowDocument(options?: DocumentOptions) {
-            return InstanceFromProto(Prototypes.get(DocumentType.SCHEMAROW), undefined, { ...(options || {}) });
-        }
-
         export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) {
             return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { freezeChildren: 'remove|add', ...options, viewType: CollectionViewType.Docking, _viewType: CollectionViewType.Docking, dockingConfig: config }, id);
         }
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index e0d0101a2..4fa5d80e2 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -126,16 +126,10 @@
     }
 }
 
-.schema-row-wrapper {
-    max-height: 70px;
-    overflow: hidden;
-}
-
 .schema-header-row,
 .schema-row {
     display: flex;
     flex-direction: row;
-    height: 100%;
     max-height: 70px;
     overflow: auto;
 
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index c9f934aec..29b22c0d5 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,29 +1,28 @@
 import React = require('react');
-import { action, computed, observable, ObservableMap, ObservableSet, trace, untracked } from 'mobx';
+import { action, computed, observable, ObservableMap, ObservableSet, untracked } from 'mobx';
 import { observer } from 'mobx-react';
-import { DataSym, Doc, DocListCast, Opt, StrListCast } from '../../../../fields/Doc';
+import { Doc, DocListCast, Opt } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { RichTextField } from '../../../../fields/RichTextField';
 import { listSpec } from '../../../../fields/Schema';
 import { BoolCast, Cast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents, smoothScroll, Utils } from '../../../../Utils';
+import { emptyFunction, returnEmptyString, setupMoveUpEvents, Utils } from '../../../../Utils';
 import { Docs, DocUtils } from '../../../documents/Documents';
 import { DragManager } from '../../../util/DragManager';
 import { SelectionManager } from '../../../util/SelectionManager';
+import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
 import { ContextMenu } from '../../ContextMenu';
 import { ContextMenuProps } from '../../ContextMenuItem';
 import { EditableView } from '../../EditableView';
+import { DocumentView } from '../../nodes/DocumentView';
 import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
 import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
-import { DocFocusOptions, DocumentView, ViewAdjustment } from '../../nodes/DocumentView';
-import { DefaultStyleProvider } from '../../StyleProvider';
-import { Transform } from '../../../util/Transform';
 
 export enum ColumnType {
     Number,
@@ -33,7 +32,7 @@ export enum ColumnType {
     Image,
 }
 
-const defaultColumnKeys: string[] = ['title', 'type', 'author', 'text', 'data', 'tags'];
+const defaultColumnKeys: string[] = ['title', 'type', 'author', 'text', 'data', 'creationDate'];
 
 @observer
 export class CollectionSchemaView extends CollectionSubView() {
@@ -399,25 +398,6 @@ export class CollectionSchemaView extends CollectionSubView() {
         ContextMenu.Instance.displayMenu(x, y, undefined, true);
     };
 
-    focusDocument = (doc: Doc, options: DocFocusOptions) => {
-        Doc.BrushDoc(doc);
-
-        let focusSpeed = 0;
-        const found = this._mainCont && Array.from(this._mainCont.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) {
-                smoothScroll((focusSpeed = options.zoomTime ?? 500), this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc);
-            }
-        }
-        const endFocus = async (moved: boolean) => options?.afterFocus?.(moved) ?? ViewAdjustment.doNothing;
-        this.props.focus(this.rootDoc, {
-            ...options,
-            afterFocus: (didFocus: boolean) => new Promise<ViewAdjustment>(res => setTimeout(async () => res(await endFocus(didFocus)), focusSpeed)),
-        });
-    };
-
     isChildContentActive = () =>
         this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : this.props.childDocumentsActive?.() === false || this.rootDoc.childDocumentsActive === false ? false : undefined;
 
@@ -465,52 +445,24 @@ export class CollectionSchemaView extends CollectionSubView() {
                             let dref: Opt<DocumentView>;
 
                             return (
-                                <div className="schema-row-wrapper">
-                                    <DocumentView
-                                        {...this.props}
-                                        ref={r => (dref = r || undefined)}
-                                        LayoutTemplate={this.props.childLayoutTemplate}
-                                        LayoutTemplateString={SchemaRowBox.LayoutString(this.props.fieldKey)}
-                                        renderDepth={this.props.renderDepth + 1}
-                                        Document={doc}
-                                        DataDoc={dataDoc}
-                                        ContainingCollectionView={this.props.CollectionView}
-                                        ContainingCollectionDoc={this.Document}
-                                        PanelWidth={this.props.PanelWidth}
-                                        PanelHeight={() => 70}
-                                        styleProvider={DefaultStyleProvider}
-                                        focus={this.focusDocument}
-                                        docFilters={this.childDocFilters}
-                                        docRangeFilters={this.childDocRangeFilters}
-                                        searchFilterDocs={this.searchFilterDocs}
-                                        rootSelected={this.rootSelected}
-                                        ScreenToLocalTransform={() => this.getDocTransform(doc, dref)}
-                                        bringToFront={emptyFunction}
-                                        isContentActive={this.isChildContentActive}
-                                        hideDecorations={true}
-                                        hideTitle={true}
-                                        hideDocumentButtonBar={true}
-                                    />
-                                </div>
+                                <SchemaRowBox
+                                    {...this.props}
+                                    key={index}
+                                    Document={doc}
+                                    ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+                                    ContainingCollectionView={this.props.CollectionView}
+                                    rowIndex={index}
+                                    columnKeys={this.columnKeys}
+                                    columnWidths={this.displayColumnWidths}
+                                    rowMenuWidth={CollectionSchemaView._rowMenuWidth}
+                                    selectedDocs={this._selectedDocs}
+                                    selectRow={this.selectRow}
+                                    startDrag={this.startDrag}
+                                    dragging={this._isDragging}
+                                    dropIndex={this.setDropIndex}
+                                    addRowRef={this.addRowRef}
+                                />
                             );
-
-                            // <SchemaRowBox
-                            //     {...this.props}
-                            //     key={index}
-                            //     Document={doc}
-                            //     ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                            //     ContainingCollectionView={this.props.CollectionView}
-                            //     rowIndex={index}
-                            //     columnKeys={this.columnKeys}
-                            //     columnWidths={this.displayColumnWidths}
-                            //     rowMenuWidth={CollectionSchemaView._rowMenuWidth}
-                            //     selectedDocs={this._selectedDocs}
-                            //     selectRow={this.selectRow}
-                            //     startDrag={this.startDrag}
-                            //     dragging={this._isDragging}
-                            //     dropIndex={this.setDropIndex}
-                            //     addRowRef={this.addRowRef}
-                            // />
                         })}
                     </div>
                 </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index a6a5f66ab..8e6d3d78a 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -40,7 +40,7 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
             case ColumnType.Boolean:
                 return (
                     <>
-                        <input type="checkbox" name="" id="" value={this._newFieldDefault ?? false} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />
+                        <input type="checkbox" name="" id="" value={this._newFieldDefault} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.checked))} />
                         {this._newFieldDefault ? 'true' : 'false'}
                     </>
                 );
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index f790e9dbf..2cf0a1b79 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -1,20 +1,17 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, ObservableMap, ObservableSet } from 'mobx';
+import { action, ObservableSet } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, StrListCast } from '../../../../fields/Doc';
+import { Doc } from '../../../../fields/Doc';
+import { DragManager } from '../../../util/DragManager';
 import { undoBatch } from '../../../util/UndoManager';
 import { ViewBoxBaseComponent } from '../../DocComponent';
 import { Colors } from '../../global/globalEnums';
-import { FieldView, FieldViewProps } from '../../nodes/FieldView';
+import { OpenWhere } from '../../nodes/DocumentView';
+import { FieldViewProps } from '../../nodes/FieldView';
 import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
-import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
-import { DragManager } from '../../../util/DragManager';
-import { OpenWhere } from '../../nodes/DocumentView';
-import { Cast } from '../../../../fields/Types';
-import { listSpec } from '../../../../fields/Schema';
-import { CollectionSchemaView } from './CollectionSchemaView';
+import { setupMoveUpEvents, emptyFunction } from '../../../../Utils';
 
 export interface SchemaRowBoxProps extends FieldViewProps {
     rowIndex: number;
@@ -30,61 +27,37 @@ export interface SchemaRowBoxProps extends FieldViewProps {
 }
 
 @observer
-export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
-    public static LayoutString(fieldKey: string) {
-        return FieldView.LayoutString(SchemaRowBox, fieldKey);
-    }
-
+export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
     private _ref: HTMLDivElement | null = null;
 
     bounds = () => this._ref?.getBoundingClientRect();
 
-    @computed get columnKeys() {
-        return StrListCast(this.props.ContainingCollectionDoc?.columnKeys);
-    }
-
-    @computed get storedColumnWidths() {
-        let widths = Cast(
-            this.props.ContainingCollectionDoc?.columnWidths,
-            listSpec('number'),
-            this.columnKeys.map(() => (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth) / this.columnKeys.length)
-        );
-
-        const totalWidth = widths.reduce((sum, width) => sum + width, 0);
-        if (totalWidth !== this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth) {
-            widths = widths.map(w => {
-                const proportion = w / totalWidth;
-                return proportion * (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth);
-            });
-        }
-
-        return widths;
-    }
+    isSelected = () => this.props.selectedDocs.has(this.props.Document);
 
     @action
     onRowPointerDown = (e: React.PointerEvent) => {
         e.stopPropagation();
 
-        // setupMoveUpEvents(
-        //     this,
-        //     e,
-        //     e => this.props.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex),
-        //     emptyFunction,
-        //     e => this.props.selectRow(e, this.props.Document, this._ref!, this.props.rowIndex)
-        // );
+        setupMoveUpEvents(
+            this,
+            e,
+            e => this.props.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex),
+            emptyFunction,
+            e => this.props.selectRow(e, this.props.Document, this._ref!, this.props.rowIndex)
+        );
     };
 
     onPointerEnter = (e: any) => {
-        // if (!this.props.dragging) return;
+        if (!this.props.dragging) return;
         document.removeEventListener('pointermove', this.onPointerMove);
         document.addEventListener('pointermove', this.onPointerMove);
     };
 
     onPointerMove = (e: any) => {
-        // if (!this.props.dragging) return;
+        if (!this.props.dragging) return;
         let dragIsRow: boolean = true;
         DragManager.docsBeingDragged.forEach(doc => {
-            // dragIsRow = this.props.selectedDocs.has(doc);
+            dragIsRow = this.props.selectedDocs.has(doc);
         });
         if (this._ref && dragIsRow) {
             const rect = this._ref.getBoundingClientRect();
@@ -94,11 +67,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
             if (y <= halfLine) {
                 this._ref.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
                 this._ref.style.borderBottom = '0px';
-                // this.props.dropIndex(this.props.rowIndex);
+                this.props.dropIndex(this.props.rowIndex);
             } else if (y > halfLine) {
                 this._ref.style.borderTop = '0px';
                 this._ref.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`;
-                // this.props.dropIndex(this.props.rowIndex + 1);
+                this.props.dropIndex(this.props.rowIndex + 1);
             }
         }
     };
@@ -115,22 +88,19 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return (
             <div
                 className="schema-row"
-                style={this.props.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE } : {}}
-                // style={this.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE, opacity: this.props.dragging ? 0.5 : 1 } : {}}
-                // onPointerDown={this.onRowPointerDown}
-                // onPointerEnter={this.onPointerEnter}
+                style={this.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE, opacity: this.props.dragging ? 0.5 : 1 } : {}}
+                onPointerDown={this.onRowPointerDown}
+                onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
-                    // row && this.props.addRowRef(this.props.Document, row);
+                    row && this.props.addRowRef(this.props.Document, row);
                     this._ref = row;
                 }}>
                 <div
                     className="row-menu"
-                    style={
-                        {
-                            /* width: this.props.rowMenuWidth */
-                        }
-                    }>
+                    style={{
+                        width: this.props.rowMenuWidth,
+                    }}>
                     <div
                         className="schema-row-button"
                         onPointerDown={undoBatch(e => {
@@ -149,8 +119,8 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     </div>
                 </div>
                 <div className="row-cells">
-                    {this.columnKeys.map((key, index) => (
-                        <SchemaTableCell key={key} Document={this.props.Document} fieldKey={key} columnWidth={this.storedColumnWidths[index]} />
+                    {this.props.columnKeys.map((key, index) => (
+                        <SchemaTableCell key={key} Document={this.props.Document} fieldKey={key} columnWidth={this.props.columnWidths[index]} />
                     ))}
                 </div>
             </div>
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 459554ebe..569579996 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -44,7 +44,6 @@ import { WebBox } from './WebBox';
 import React = require('react');
 import XRegExp = require('xregexp');
 import { LoadingBox } from './LoadingBox';
-import { SchemaRowBox } from '../collections/collectionSchema/SchemaRowBox';
 
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
@@ -269,7 +268,6 @@ export class DocumentContentsView extends React.Component<
                     HTMLtag,
                     ComparisonBox,
                     LoadingBox,
-                    SchemaRowBox,
                 }}
                 bindings={bindings}
                 jsx={layoutFrame}
-- 
cgit v1.2.3-70-g09d2


From ea73082dc0293a0bafde20b0f82d674b7ca230f9 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 30 Jan 2023 22:14:52 -0500
Subject: basic sorting

---
 .../collectionSchema/CollectionSchemaView.tsx      | 32 +++++++++++++++--
 .../collectionSchema/SchemaColumnHeader.tsx        | 42 ++++++++++++++++++++++
 .../collectionSchema/SchemaTableCell.tsx           |  2 --
 3 files changed, 72 insertions(+), 4 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 29b22c0d5..4fb3f68c1 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,12 +1,12 @@
 import React = require('react');
 import { action, computed, observable, ObservableMap, ObservableSet, untracked } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, DocListCast, Opt } from '../../../../fields/Doc';
+import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { RichTextField } from '../../../../fields/RichTextField';
 import { listSpec } from '../../../../fields/Schema';
-import { BoolCast, Cast, StrCast } from '../../../../fields/Types';
+import { BoolCast, Cast, NumCast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { emptyFunction, returnEmptyString, setupMoveUpEvents, Utils } from '../../../../Utils';
 import { Docs, DocUtils } from '../../../documents/Documents';
@@ -89,6 +89,31 @@ export class CollectionSchemaView extends CollectionSubView() {
         return this._displayColumnWidths ?? this.storedColumnWidths;
     }
 
+    @computed get sortField() {
+        return StrCast(this.layoutDoc.sortField, 'creationDate');
+    }
+
+    @computed get sortDesc() {
+        return BoolCast(this.layoutDoc.sortDesc);
+    }
+
+    @undoBatch
+    @action
+    setSort = (field: string, desc: boolean) => {
+        this.layoutDoc.sortField = field;
+        this.layoutDoc.sortDesc = desc;
+
+        this.childDocs.sort((docA, docB) => {
+            const aStr = Field.toString(docA[field] as Field);
+            const bStr = Field.toString(docB[field] as Field);
+            var out = 0;
+            if (aStr < bStr) out = -1;
+            if (aStr > bStr) out = 1;
+            if (desc) out *= -1;
+            return out;
+        });
+    };
+
     @undoBatch
     @action
     changeColumnKey = (index: number, newKey: string, defaultVal?: any) => {
@@ -430,6 +455,9 @@ export class CollectionSchemaView extends CollectionSubView() {
                                     columnKeys={this.columnKeys}
                                     columnWidths={this.displayColumnWidths}
                                     possibleKeys={this.documentKeys}
+                                    sortField={this.sortField}
+                                    sortDesc={this.sortDesc}
+                                    setSort={this.setSort}
                                     changeColumnKey={this.changeColumnKey}
                                     addColumn={this.addColumn}
                                     removeColumn={this.removeColumn}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 8e6d3d78a..9d5dfe507 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -11,6 +11,9 @@ export interface SchemaColumnHeaderProps {
     columnWidths: number[];
     columnIndex: number;
     possibleKeys: string[];
+    sortField: string;
+    sortDesc: boolean;
+    setSort: (field: string, desc: boolean) => void;
     changeColumnKey: (index: number, newKey: string, defaultVal?: any) => void;
     addColumn: (index: number, key: string, defaultVal?: any) => void;
     removeColumn: (index: number) => void;
@@ -27,12 +30,24 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
     @observable _newFieldWarning: string = '';
     @observable _menuValue: string = '';
     @observable _menuOptions: string[] = [];
+    @observable _filterVisible: boolean = false;
     private _makeNewColumn = false;
 
     @computed get fieldKey() {
         return this.props.columnKeys[this.props.columnIndex];
     }
 
+    @action
+    sortClicked = (e: React.PointerEvent) => {
+        e.stopPropagation();
+        e.preventDefault();
+        if (this.props.sortField == this.fieldKey) {
+            this.props.setSort(this.fieldKey, !this.props.sortDesc);
+        } else {
+            this.props.setSort(this.fieldKey, false);
+        }
+    };
+
     @computed get fieldDefaultInput() {
         switch (this._newFieldType) {
             case ColumnType.Number:
@@ -138,6 +153,14 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
         );
     }
 
+    @computed get columnFilterMenu() {
+        return (
+            <div className="schema-column-menu">
+                <input className="schema-key-search-input" type="text" value={this._menuValue} onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
+            </div>
+        );
+    }
+
     onSearchKeyDown = (e: React.KeyboardEvent) => {
         switch (e.key) {
             case 'Enter':
@@ -178,6 +201,7 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
         if (this._menuVisible) {
             this._menuVisible = false;
         } else {
+            this._filterVisible = false;
             this._menuVisible = true;
             this._menuValue = '';
             this._menuOptions = this.props.possibleKeys;
@@ -190,6 +214,17 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
         }
     };
 
+    @action
+    toggleFilterMenu = () => {
+        console.log(this._filterVisible);
+        if (this._filterVisible) {
+            this._filterVisible = false;
+        } else {
+            this._filterVisible = true;
+            this._menuVisible = false;
+        }
+    };
+
     render() {
         return (
             <div className="schema-column-header" style={{ width: this.props.columnWidths[this.props.columnIndex] }}>
@@ -218,11 +253,18 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
                         }}>
                         <FontAwesomeIcon icon="trash" />
                     </div>
+                    <div className="schema-header-button" onPointerDown={this.sortClicked}>
+                        <FontAwesomeIcon icon="caret-right" style={this.props.sortField == this.fieldKey ? { transform: `rotate(${this.props.sortDesc ? '270deg' : '90deg'})` } : {}} />
+                    </div>
+                    <div className="schema-header-button" onPointerDown={e => this.toggleFilterMenu()}>
+                        <FontAwesomeIcon icon="filter" />
+                    </div>
                 </div>
 
                 <div className="schema-column-resizer right" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex, false)}></div>
 
                 {this._menuVisible && this.renderColumnMenu}
+                {this._filterVisible && this.columnFilterMenu}
             </div>
         );
     }
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 7e2fa1f6f..5d9474173 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -14,8 +14,6 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     render() {
         return (
             <div className="schema-table-cell" style={{ width: this.props.columnWidth }}>
-                {/* {StrCast(this.props.Document[this.props.fieldKey])} */}
-                {/* Field.toKeyValueString(this.props.Document, this.props.fieldKey) */}
                 {Field.toString(this.props.Document[this.props.fieldKey] as Field)}
             </div>
         );
-- 
cgit v1.2.3-70-g09d2


From ca3868b494bfd00c0349424f622bb5010b0e1197 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Thu, 9 Feb 2023 00:03:32 -0500
Subject: doc preview and arrow key movement

---
 package-lock.json                                  |  50 ++++----
 .../collectionSchema/CollectionSchemaView.scss     |   8 ++
 .../collectionSchema/CollectionSchemaView.tsx      | 136 ++++++++++++++++++---
 .../collectionSchema/SchemaColumnHeader.tsx        |   3 +-
 4 files changed, 156 insertions(+), 41 deletions(-)

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

diff --git a/package-lock.json b/package-lock.json
index f63aaf774..307221f4a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2288,7 +2288,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": {
@@ -2639,7 +2639,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="
                 }
             }
         },
@@ -2738,7 +2738,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",
@@ -3530,7 +3530,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",
@@ -3600,7 +3600,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",
@@ -4577,7 +4577,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",
@@ -4587,7 +4587,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-brotli": {
             "version": "1.3.8",
@@ -5295,7 +5295,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",
@@ -6201,7 +6201,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"
@@ -6331,7 +6331,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",
@@ -8678,7 +8678,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",
@@ -9316,14 +9316,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",
@@ -9916,7 +9916,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",
@@ -10969,7 +10969,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"
             }
@@ -11393,7 +11393,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",
@@ -11654,7 +11654,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"
             },
@@ -11662,7 +11662,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="
                 }
             }
         },
@@ -19974,7 +19974,7 @@
                 "component-emitter": {
                     "version": "1.2.1",
                     "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
-                    "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
+                    "integrity": "sha512-jPatnhd33viNplKjqXKRkGU345p263OIWzDL2wH3LGIGp5Kojo+uXizHmOADRvhGFFTnJqX3jBAKP6vvmSDKcA=="
                 },
                 "debug": {
                     "version": "4.1.1",
@@ -19987,7 +19987,7 @@
                 "isarray": {
                     "version": "2.0.1",
                     "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
-                    "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
+                    "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ=="
                 }
             }
         },
@@ -20852,7 +20852,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",
@@ -21223,7 +21223,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
                 }
             }
@@ -22424,7 +22424,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"
@@ -22433,7 +22433,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": {
@@ -22974,7 +22974,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 4fa5d80e2..bd0fc11b3 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -3,6 +3,8 @@
 .collectionSchemaView {
     cursor: default;
     height: 100%;
+    display: flex;
+    flex-direction: row;
 
     .schema-table {
         background-color: $white;
@@ -124,6 +126,12 @@
             flex-direction: row;
         }
     }
+
+    .schema-preview-divider {
+        height: 100%;
+        background: black;
+        cursor: ew-resize;
+    }
 }
 
 .schema-header-row,
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 4fb3f68c1..5d4777e12 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -8,7 +8,7 @@ import { RichTextField } from '../../../../fields/RichTextField';
 import { listSpec } from '../../../../fields/Schema';
 import { BoolCast, Cast, NumCast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
-import { emptyFunction, returnEmptyString, setupMoveUpEvents, Utils } from '../../../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../../../Utils';
 import { Docs, DocUtils } from '../../../documents/Documents';
 import { DragManager } from '../../../util/DragManager';
 import { SelectionManager } from '../../../util/SelectionManager';
@@ -23,6 +23,7 @@ import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
+import { DefaultStyleProvider } from '../../StyleProvider';
 
 export enum ColumnType {
     Number,
@@ -43,10 +44,12 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _minColWidth: number = 150;
 
     public static _rowMenuWidth: number = 100;
+    public static _previewDividerWidth: number = 4;
     @observable _selectedDocs: ObservableSet = new ObservableSet<Doc>();
     @observable _rowEles: ObservableMap = new ObservableMap<Doc, HTMLDivElement>();
     @observable _isDragging: boolean = false;
     @observable _displayColumnWidths: number[] | undefined;
+    @observable _previewDoc: Doc | undefined;
 
     get documentKeys() {
         const docs = this.childDocs;
@@ -63,6 +66,14 @@ export class CollectionSchemaView extends CollectionSubView() {
         return Array.from(Object.keys(keys));
     }
 
+    @computed get previewWidth() {
+        return NumCast(this.props.Document.schemaPreviewWidth);
+    }
+
+    @computed get tableWidth() {
+        return this.props.PanelWidth() - this.previewWidth - CollectionSchemaView._previewDividerWidth;
+    }
+
     @computed get columnKeys() {
         return Cast(this.layoutDoc.columnKeys, listSpec('string'), defaultColumnKeys);
     }
@@ -71,14 +82,14 @@ export class CollectionSchemaView extends CollectionSubView() {
         let widths = Cast(
             this.layoutDoc.columnWidths,
             listSpec('number'),
-            this.columnKeys.map(() => (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth) / this.columnKeys.length)
+            this.columnKeys.map(() => (this.tableWidth - CollectionSchemaView._rowMenuWidth) / this.columnKeys.length)
         );
 
         const totalWidth = widths.reduce((sum, width) => sum + width, 0);
-        if (totalWidth !== this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth) {
+        if (totalWidth !== this.tableWidth - CollectionSchemaView._rowMenuWidth) {
             widths = widths.map(w => {
                 const proportion = w / totalWidth;
-                return proportion * (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth);
+                return proportion * (this.tableWidth - CollectionSchemaView._rowMenuWidth);
             });
         }
 
@@ -97,6 +108,42 @@ export class CollectionSchemaView extends CollectionSubView() {
         return BoolCast(this.layoutDoc.sortDesc);
     }
 
+    componentDidMount() {
+        document.addEventListener('keydown', this.onKeyDown);
+    }
+
+    componentWillUnmount() {
+        document.removeEventListener('keydown', this.onKeyDown);
+    }
+
+    @action
+    onKeyDown = (e: KeyboardEvent) => {
+        if (this._selectedDocs.size > 0) {
+            if (e.key == 'ArrowDown') {
+                const lastDoc = Array.from(this._selectedDocs.values()).lastElement();
+                const lastIndex = this.childDocs.indexOf(lastDoc);
+                if (lastIndex >= 0 && lastIndex < this.childDocs.length - 1) {
+                    this._selectedDocs.clear();
+                    const newDoc = this.childDocs[lastIndex + 1];
+                    this._selectedDocs.add(newDoc);
+                    SelectionManager.SelectSchemaViewDoc(newDoc);
+                    this._previewDoc = newDoc;
+                }
+            }
+            if (e.key == 'ArrowUp') {
+                const firstDoc = Array.from(this._selectedDocs.values())[0];
+                const firstIndex = this.childDocs.indexOf(firstDoc);
+                if (firstIndex > 0) {
+                    this._selectedDocs.clear();
+                    const newDoc = this.childDocs[firstIndex - 1];
+                    this._selectedDocs.add(newDoc);
+                    SelectionManager.SelectSchemaViewDoc(newDoc);
+                    this._previewDoc = newDoc;
+                }
+            }
+        }
+    };
+
     @undoBatch
     @action
     setSort = (field: string, desc: boolean) => {
@@ -134,10 +181,10 @@ export class CollectionSchemaView extends CollectionSubView() {
         }
 
         let currWidths = [...this.storedColumnWidths];
-        const newColWidth = this.props.PanelWidth() / (currWidths.length + 1);
+        const newColWidth = this.tableWidth / (currWidths.length + 1);
         currWidths = currWidths.map(w => {
-            const proportion = w / (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth);
-            return proportion * (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth - newColWidth);
+            const proportion = w / (this.tableWidth - CollectionSchemaView._rowMenuWidth);
+            return proportion * (this.tableWidth - CollectionSchemaView._rowMenuWidth - newColWidth);
         });
         currWidths.splice(index + 1, 0, newColWidth);
         this.layoutDoc.columnWidths = new List<number>(currWidths);
@@ -159,8 +206,8 @@ export class CollectionSchemaView extends CollectionSubView() {
         let currWidths = [...this.storedColumnWidths];
         const removedColWidth = currWidths[index];
         currWidths = currWidths.map(w => {
-            const proportion = w / (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth - removedColWidth);
-            return proportion * (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth);
+            const proportion = w / (this.tableWidth - CollectionSchemaView._rowMenuWidth - removedColWidth);
+            return proportion * (this.tableWidth - CollectionSchemaView._rowMenuWidth);
         });
         currWidths.splice(index, 1);
         this.layoutDoc.columnWidths = new List<number>(currWidths);
@@ -283,6 +330,12 @@ export class CollectionSchemaView extends CollectionSubView() {
         } else {
             SelectionManager.SelectSchemaViewDoc(undefined);
         }
+
+        if (this._selectedDocs.size == 1) {
+            this._previewDoc = Array.from(this._selectedDocs)[0];
+        } else {
+            this._previewDoc = undefined;
+        }
     };
 
     @action
@@ -346,6 +399,21 @@ export class CollectionSchemaView extends CollectionSubView() {
         return true;
     };
 
+    onDividerDown = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, emptyFunction);
+    };
+
+    @action
+    onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => {
+        // const nativeWidth = this._previewCont!.getBoundingClientRect();
+        // const minWidth = 40;
+        // const maxWidth = 1000;
+        // const movedWidth = this.props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0];
+        // const width = movedWidth < minWidth ? minWidth : movedWidth > maxWidth ? maxWidth : movedWidth;
+        this.props.Document.schemaPreviewWidth = this.previewWidth - delta[0];
+        return false;
+    };
+
     @action
     addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
         if (!value && !forceEmptyNote) return false;
@@ -440,11 +508,14 @@ export class CollectionSchemaView extends CollectionSubView() {
                     this._ref = ele;
                     this.createDashEventsTarget(ele);
                 }}
-                onPointerDown={action(() => {
-                    this._selectedDocs.clear();
-                })}
                 onDrop={this.onExternalDrop.bind(this)}>
-                <div className="schema-table">
+                <div
+                    className="schema-table"
+                    onPointerDown={action(() => {
+                        this._selectedDocs.clear();
+                        SelectionManager.SelectSchemaViewDoc(undefined);
+                        this._previewDoc = undefined;
+                    })}>
                     <div className="schema-header-row">
                         <div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}></div>
                         {this.columnKeys.map((key, index) => {
@@ -467,7 +538,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                             );
                         })}
                     </div>
-                    <div className="schema-table-content">
+                    <div className="schema-table-content" onPointerDown={e => e.stopPropagation()}>
                         {this.childDocs.map((doc: Doc, index: number) => {
                             const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.DataDoc;
                             let dref: Opt<DocumentView>;
@@ -493,8 +564,43 @@ export class CollectionSchemaView extends CollectionSubView() {
                             );
                         })}
                     </div>
+                    <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} />
                 </div>
-                <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} />
+                <div className="schema-preview-divider" style={{ width: CollectionSchemaView._previewDividerWidth }} onPointerDown={this.onDividerDown}></div>
+                {this.previewWidth > 0 && (
+                    <div style={{ width: `${this.previewWidth}px` }}>
+                        {this._previewDoc && (
+                            <DocumentView
+                                Document={this._previewDoc}
+                                DataDoc={undefined}
+                                fitContentsToBox={returnTrue}
+                                dontCenter={'y'}
+                                focus={DocUtils.DefaultFocus}
+                                renderDepth={this.props.renderDepth}
+                                rootSelected={this.rootSelected}
+                                PanelWidth={() => this.previewWidth}
+                                PanelHeight={this.props.PanelHeight}
+                                isContentActive={returnTrue}
+                                isDocumentActive={returnFalse}
+                                ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-this.tableWidth, 0)}
+                                docFilters={this.childDocFilters}
+                                docRangeFilters={this.childDocRangeFilters}
+                                searchFilterDocs={this.searchFilterDocs}
+                                styleProvider={DefaultStyleProvider}
+                                docViewPath={returnEmptyDoclist}
+                                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+                                ContainingCollectionView={this.props.CollectionView}
+                                moveDocument={this.props.moveDocument}
+                                addDocument={this.props.addDocument}
+                                removeDocument={this.props.removeDocument}
+                                whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
+                                addDocTab={this.props.addDocTab}
+                                pinToPres={this.props.pinToPres}
+                                bringToFront={returnFalse}
+                            />
+                        )}
+                    </div>
+                )}
             </div>
         );
     }
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 9d5dfe507..2e303f91c 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -5,6 +5,7 @@ import { observer } from 'mobx-react';
 import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
 import './CollectionSchemaView.scss';
 import { ColumnType } from './CollectionSchemaView';
+import { Colors } from 'browndash-components';
 
 export interface SchemaColumnHeaderProps {
     columnKeys: string[];
@@ -253,7 +254,7 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
                         }}>
                         <FontAwesomeIcon icon="trash" />
                     </div>
-                    <div className="schema-header-button" onPointerDown={this.sortClicked}>
+                    <div className="schema-header-button" onPointerDown={this.sortClicked} style={this.props.sortField == this.fieldKey ? { backgroundColor: Colors.MEDIUM_BLUE } : {}}>
                         <FontAwesomeIcon icon="caret-right" style={this.props.sortField == this.fieldKey ? { transform: `rotate(${this.props.sortDesc ? '270deg' : '90deg'})` } : {}} />
                     </div>
                     <div className="schema-header-button" onPointerDown={e => this.toggleFilterMenu()}>
-- 
cgit v1.2.3-70-g09d2


From b55a757175051457c9260f80a1de937901f5cfff Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 6 Mar 2023 17:53:36 -0500
Subject: moved column menu

---
 .../collectionSchema/CollectionSchemaView.scss     | 144 +++++++--------
 .../collectionSchema/CollectionSchemaView.tsx      | 185 ++++++++++++++++++-
 .../collectionSchema/SchemaColumnHeader.tsx        | 199 +--------------------
 .../collectionSchema/SchemaTableCell.tsx           |  17 +-
 4 files changed, 254 insertions(+), 291 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 5c0b6d88b..931645857 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -9,6 +9,77 @@
     .schema-table {
         background-color: $white;
 
+        .schema-column-menu {
+            background: $light-gray;
+            position: absolute;
+            min-width: 200px;
+            display: flex;
+            flex-direction: column;
+            align-items: flex-start;
+            z-index: 1;
+
+            .schema-key-search-input {
+                width: calc(100% - 20px);
+                margin: 10px;
+            }
+
+            .schema-key-search-result {
+                cursor: pointer;
+                padding: 2px 10px;
+                width: 100%;
+
+                &:hover {
+                    background-color: $medium-gray;
+                }
+            }
+
+            .schema-key-search,
+            .schema-new-key-options {
+                width: 100%;
+                display: flex;
+                flex-direction: column;
+                align-items: flex-start;
+            }
+
+            .schema-new-key-options {
+                margin: 10px;
+                .schema-key-warning {
+                    color: red;
+                    font-weight: normal;
+                    align-self: center;
+                }
+            }
+
+            .schema-key-list {
+                width: 100%;
+                max-height: 300px;
+                overflow-y: auto;
+            }
+
+            .schema-key-type-option {
+                margin: 2px 0px;
+
+                input {
+                    margin-right: 5px;
+                }
+            }
+
+            .schema-key-default-val {
+                margin: 5px 0;
+            }
+
+            .schema-column-menu-button {
+                cursor: pointer;
+                padding: 2px 5px;
+                background: $medium-blue;
+                border-radius: 9999px;
+                color: $white;
+                width: fit-content;
+                margin: 5px;
+                align-self: center;
+            }
+        }
+
         .schema-header-row {
             justify-content: flex-end;
 
@@ -19,6 +90,7 @@
                 justify-content: space-between;
                 align-items: center;
                 padding: 0;
+                z-index: 1;
 
                 .schema-column-title {
                     flex-grow: 2;
@@ -46,78 +118,6 @@
                 .schema-column-resizer.left {
                     align-self: flex-start;
                 }
-
-                .schema-column-menu {
-                    background: $light-gray;
-                    width: inherit;
-                    position: absolute;
-                    top: 35px;
-                    min-width: 200px;
-                    display: flex;
-                    flex-direction: column;
-                    align-items: flex-start;
-
-                    .schema-key-search-input {
-                        width: calc(100% - 20px);
-                        margin: 10px;
-                    }
-
-                    .schema-key-search-result {
-                        cursor: pointer;
-                        padding: 2px 10px;
-                        width: 100%;
-
-                        &:hover {
-                            background-color: $medium-gray;
-                        }
-                    }
-
-                    .schema-key-search,
-                    .schema-new-key-options {
-                        width: 100%;
-                        display: flex;
-                        flex-direction: column;
-                        align-items: flex-start;
-                    }
-
-                    .schema-new-key-options {
-                        margin: 10px;
-                        .schema-key-warning {
-                            color: red;
-                            font-weight: normal;
-                            align-self: center;
-                        }
-                    }
-
-                    .schema-key-list {
-                        width: 100%;
-                        max-height: 300px;
-                        overflow-y: auto;
-                    }
-
-                    .schema-key-type-option {
-                        margin: 2px 0px;
-
-                        input {
-                            margin-right: 5px;
-                        }
-                    }
-
-                    .schema-key-default-val {
-                        margin: 5px 0;
-                    }
-
-                    .schema-column-menu-button {
-                        cursor: pointer;
-                        padding: 2px 5px;
-                        background: $medium-blue;
-                        border-radius: 9999px;
-                        color: $white;
-                        width: fit-content;
-                        margin: 5px;
-                        align-self: center;
-                    }
-                }
             }
         }
 
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index c52a7f3e4..fd7790c4b 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -26,6 +26,7 @@ import { SchemaRowBox } from './SchemaRowBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
 import { DocumentManager } from '../../../util/DocumentManager';
 import { ScriptField } from '../../../../fields/ScriptField';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 
 export enum ColumnType {
     Number,
@@ -43,16 +44,25 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _selectedDocSortedArray: Doc[] = [];
     private _closestDropIndex: number = 0;
     private _previewRef: HTMLDivElement | null = null;
+    private _makeNewColumn: boolean = false;
 
     public static _rowHeight: number = 50;
     public static _minColWidth: number = 150;
     public static _rowMenuWidth: number = 100;
     public static _previewDividerWidth: number = 4;
+
     @observable _lastSelectedRow: number | undefined;
     @observable _selectedDocs: ObservableSet = new ObservableSet<Doc>();
     @observable _rowEles: ObservableMap = new ObservableMap<Doc, HTMLDivElement>();
     @observable _isDragging: boolean = false;
     @observable _displayColumnWidths: number[] | undefined;
+    @observable _columnMenuIndex: number | undefined;
+    @observable _menuOptions: string[] = [];
+    @observable _newFieldWarning: string = '';
+    @observable _makeNewField: boolean = false;
+    @observable _newFieldDefault: any = 0;
+    @observable _newFieldType: ColumnType = ColumnType.Number;
+    @observable _menuValue: string = '';
 
     get documentKeys() {
         const docs = this.childDocs;
@@ -154,8 +164,6 @@ export class CollectionSchemaView extends CollectionSubView() {
         this.layoutDoc.sortField = field;
         this.layoutDoc.sortDesc = desc;
 
-        console.log(field, desc);
-
         if (field === undefined) return;
 
         this.childDocs.sort((docA, docB) => {
@@ -189,7 +197,7 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @undoBatch
     @action
-    addColumn = (index: number, key: string, defaultVal?: any) => {
+    addColumn = (key: string, defaultVal?: any) => {
         if (!this.documentKeys.includes(key)) {
             this.addNewKey(key, defaultVal);
         }
@@ -200,11 +208,11 @@ export class CollectionSchemaView extends CollectionSubView() {
             const proportion = w / (this.tableWidth - CollectionSchemaView._rowMenuWidth);
             return proportion * (this.tableWidth - CollectionSchemaView._rowMenuWidth - newColWidth);
         });
-        currWidths.splice(index + 1, 0, newColWidth);
+        currWidths.splice(0, 0, newColWidth);
         this.layoutDoc.columnWidths = new List<number>(currWidths);
 
         let currKeys = [...this.columnKeys];
-        currKeys.splice(index + 1, 0, key);
+        currKeys.splice(0, 0, key);
         this.layoutDoc.columnKeys = new List<string>(currKeys);
     };
 
@@ -386,6 +394,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             this.addDocument(this._selectedDocSortedArray);
             this.addDocument(pushedDocs);
             this.setSort(undefined);
+            this.clearSelection();
             return true;
         }
         return false;
@@ -543,6 +552,157 @@ export class CollectionSchemaView extends CollectionSubView() {
     isChildContentActive = () =>
         this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : this.props.childDocumentsActive?.() === false || this.rootDoc.childDocumentsActive === false ? false : undefined;
 
+    @computed get fieldDefaultInput() {
+        switch (this._newFieldType) {
+            case ColumnType.Number:
+                return <input type="number" name="" id="" value={this._newFieldDefault ?? 0} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />;
+            case ColumnType.Boolean:
+                return (
+                    <>
+                        <input type="checkbox" name="" id="" value={this._newFieldDefault} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.checked))} />
+                        {this._newFieldDefault ? 'true' : 'false'}
+                    </>
+                );
+            case ColumnType.String:
+                return <input type="text" name="" id="" value={this._newFieldDefault ?? ''} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />;
+        }
+    }
+
+    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))();
+                break;
+            case 'Escape':
+                this.toggleColumnMenu(this._columnMenuIndex);
+                break;
+        }
+    };
+
+    @action
+    setKey = (key: string, defaultVal?: any) => {
+        if (this._makeNewColumn) {
+            this.addColumn(key, defaultVal);
+        } else {
+            this.changeColumnKey(this._columnMenuIndex!, key, defaultVal);
+        }
+        this.toggleColumnMenu(this._columnMenuIndex);
+    };
+
+    @action
+    toggleColumnMenu = (index: number | undefined, newCol?: boolean) => {
+        this._makeNewColumn = false;
+        if (this._columnMenuIndex !== undefined && index === this._columnMenuIndex) {
+            this._columnMenuIndex = undefined;
+        } else {
+            this._columnMenuIndex = index;
+            this._menuValue = '';
+            this._menuOptions = this.documentKeys;
+            this._makeNewField = false;
+            this._newFieldWarning = '';
+            this._makeNewField = false;
+            if (newCol) {
+                this._makeNewColumn = true;
+            }
+        }
+    };
+
+    @action
+    updateKeySearch = (e: React.ChangeEvent<HTMLInputElement>) => {
+        this._menuValue = e.target.value;
+        this._menuOptions = this.documentKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
+    };
+
+    @computed get renderColumnMenu() {
+        const x = this.displayColumnWidths.reduce((total, curr, index) => total + (index < this._columnMenuIndex! ? curr : 0), CollectionSchemaView._rowMenuWidth);
+        return (
+            <div className="schema-column-menu" style={{ left: x }}>
+                <input className="schema-key-search-input" type="text" value={this._menuValue} onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
+                {this._makeNewField ? (
+                    <div className="schema-new-key-options">
+                        <div className="schema-key-type-option">
+                            <input
+                                type="radio"
+                                name="newFieldType"
+                                id=""
+                                checked={this._newFieldType == ColumnType.Number}
+                                onChange={action(() => {
+                                    this._newFieldType = ColumnType.Number;
+                                    this._newFieldDefault = 0;
+                                })}
+                            />
+                            number
+                        </div>
+                        <div className="schema-key-type-option">
+                            <input
+                                type="radio"
+                                name="newFieldType"
+                                id=""
+                                checked={this._newFieldType == ColumnType.Boolean}
+                                onChange={action(() => {
+                                    this._newFieldType = ColumnType.Boolean;
+                                    this._newFieldDefault = false;
+                                })}
+                            />
+                            boolean
+                        </div>
+                        <div className="schema-key-type-option">
+                            <input
+                                type="radio"
+                                name="newFieldType"
+                                id=""
+                                checked={this._newFieldType == ColumnType.String}
+                                onChange={action(() => {
+                                    this._newFieldType = ColumnType.String;
+                                    this._newFieldDefault = '';
+                                })}
+                            />
+                            string
+                        </div>
+                        <div className="schema-key-default-val">value: {this.fieldDefaultInput}</div>
+                        <div className="schema-key-warning">{this._newFieldWarning}</div>
+                        <div
+                            className="schema-column-menu-button"
+                            onPointerDown={action(e => {
+                                if (this.documentKeys.includes(this._menuValue)) {
+                                    this._newFieldWarning = 'Field already exists';
+                                } else if (this._menuValue.length === 0) {
+                                    this._newFieldWarning = 'Field cannot be an empty string';
+                                } else {
+                                    this.setKey(this._menuValue, this._newFieldDefault);
+                                }
+                            })}>
+                            done
+                        </div>
+                    </div>
+                ) : (
+                    <div className="schema-key-search">
+                        <div
+                            className="schema-column-menu-button"
+                            onPointerDown={action(e => {
+                                e.stopPropagation();
+                                this._makeNewField = true;
+                            })}>
+                            + new field
+                        </div>
+                        <div className="schema-key-list">
+                            {this._menuOptions.map(key => (
+                                <div
+                                    className="schema-key-search-result"
+                                    onPointerDown={e => {
+                                        e.stopPropagation();
+                                        this.setKey(key);
+                                    }}>
+                                    {key}
+                                </div>
+                            ))}
+                        </div>
+                    </div>
+                )}
+            </div>
+        );
+    }
+
     render() {
         return (
             <div
@@ -558,7 +718,15 @@ export class CollectionSchemaView extends CollectionSubView() {
                         this.clearSelection();
                     })}>
                     <div className="schema-header-row" style={{ height: CollectionSchemaView._rowHeight }}>
-                        <div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}></div>
+                        <div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}>
+                            <div
+                                className="schema-header-button"
+                                onPointerDown={e => {
+                                    this.toggleColumnMenu(-1, true);
+                                }}>
+                                <FontAwesomeIcon icon="plus" />
+                            </div>
+                        </div>
                         {this.columnKeys.map((key, index) => {
                             return (
                                 <SchemaColumnHeader
@@ -566,18 +734,17 @@ export class CollectionSchemaView extends CollectionSubView() {
                                     columnIndex={index}
                                     columnKeys={this.columnKeys}
                                     columnWidths={this.displayColumnWidths}
-                                    possibleKeys={this.documentKeys}
                                     sortField={this.sortField}
                                     sortDesc={this.sortDesc}
                                     setSort={this.setSort}
-                                    changeColumnKey={this.changeColumnKey}
-                                    addColumn={this.addColumn}
                                     removeColumn={this.removeColumn}
                                     resizeColumn={this.startResize}
+                                    toggleColumnMenu={this.toggleColumnMenu}
                                 />
                             );
                         })}
                     </div>
+                    {this._columnMenuIndex !== undefined && this.renderColumnMenu}
                     <div className="schema-table-content" onPointerDown={e => e.stopPropagation()}>
                         {this.childDocs.map((doc: Doc, index: number) => {
                             const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.DataDoc;
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 2e303f91c..ba63b352b 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -11,29 +11,17 @@ export interface SchemaColumnHeaderProps {
     columnKeys: string[];
     columnWidths: number[];
     columnIndex: number;
-    possibleKeys: string[];
     sortField: string;
     sortDesc: boolean;
     setSort: (field: string, desc: boolean) => void;
-    changeColumnKey: (index: number, newKey: string, defaultVal?: any) => void;
-    addColumn: (index: number, key: string, defaultVal?: any) => void;
     removeColumn: (index: number) => void;
     resizeColumn: (e: any, index: number, left: boolean) => void;
+    toggleColumnMenu: (index: number | undefined, newCol?: boolean) => void;
     // dragColumn: (e: any, index: number) => boolean;
 }
 
 @observer
 export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps> {
-    @observable _menuVisible: boolean = false;
-    @observable _makeNewField: boolean = false;
-    @observable _newFieldType: ColumnType = ColumnType.Number;
-    @observable _newFieldDefault: any = 0;
-    @observable _newFieldWarning: string = '';
-    @observable _menuValue: string = '';
-    @observable _menuOptions: string[] = [];
-    @observable _filterVisible: boolean = false;
-    private _makeNewColumn = false;
-
     @computed get fieldKey() {
         return this.props.columnKeys[this.props.columnIndex];
     }
@@ -49,146 +37,6 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
         }
     };
 
-    @computed get fieldDefaultInput() {
-        switch (this._newFieldType) {
-            case ColumnType.Number:
-                return <input type="number" name="" id="" value={this._newFieldDefault ?? 0} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />;
-            case ColumnType.Boolean:
-                return (
-                    <>
-                        <input type="checkbox" name="" id="" value={this._newFieldDefault} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.checked))} />
-                        {this._newFieldDefault ? 'true' : 'false'}
-                    </>
-                );
-            case ColumnType.String:
-                return <input type="text" name="" id="" value={this._newFieldDefault ?? ''} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />;
-        }
-    }
-
-    @computed get renderColumnMenu() {
-        return (
-            <div className="schema-column-menu">
-                <input className="schema-key-search-input" type="text" value={this._menuValue} onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
-                {this._makeNewField ? (
-                    <div className="schema-new-key-options">
-                        <div className="schema-key-type-option">
-                            <input
-                                type="radio"
-                                name="newFieldType"
-                                id=""
-                                checked={this._newFieldType == ColumnType.Number}
-                                onChange={action(() => {
-                                    this._newFieldType = ColumnType.Number;
-                                    this._newFieldDefault = 0;
-                                })}
-                            />
-                            number
-                        </div>
-                        <div className="schema-key-type-option">
-                            <input
-                                type="radio"
-                                name="newFieldType"
-                                id=""
-                                checked={this._newFieldType == ColumnType.Boolean}
-                                onChange={action(() => {
-                                    this._newFieldType = ColumnType.Boolean;
-                                    this._newFieldDefault = false;
-                                })}
-                            />
-                            boolean
-                        </div>
-                        <div className="schema-key-type-option">
-                            <input
-                                type="radio"
-                                name="newFieldType"
-                                id=""
-                                checked={this._newFieldType == ColumnType.String}
-                                onChange={action(() => {
-                                    this._newFieldType = ColumnType.String;
-                                    this._newFieldDefault = '';
-                                })}
-                            />
-                            string
-                        </div>
-                        <div className="schema-key-default-val">value: {this.fieldDefaultInput}</div>
-                        <div className="schema-key-warning">{this._newFieldWarning}</div>
-                        <div
-                            className="schema-column-menu-button"
-                            onPointerDown={action(e => {
-                                if (this.props.possibleKeys.includes(this._menuValue)) {
-                                    this._newFieldWarning = 'Field already exists';
-                                } else if (this._menuValue.length === 0) {
-                                    this._newFieldWarning = 'Field cannot be an empty string';
-                                } else {
-                                    this.setKey(this._menuValue, this._newFieldDefault);
-                                }
-                            })}>
-                            done
-                        </div>
-                    </div>
-                ) : (
-                    <div className="schema-key-search">
-                        <div
-                            className="schema-column-menu-button"
-                            onPointerDown={action(e => {
-                                e.stopPropagation();
-                                this._makeNewField = true;
-                            })}>
-                            + new field
-                        </div>
-                        <div className="schema-key-list">
-                            {this._menuOptions.map(key => (
-                                <div
-                                    className="schema-key-search-result"
-                                    onPointerDown={e => {
-                                        e.stopPropagation();
-                                        this.setKey(key);
-                                    }}>
-                                    {key}
-                                </div>
-                            ))}
-                        </div>
-                    </div>
-                )}
-            </div>
-        );
-    }
-
-    @computed get columnFilterMenu() {
-        return (
-            <div className="schema-column-menu">
-                <input className="schema-key-search-input" type="text" value={this._menuValue} onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
-            </div>
-        );
-    }
-
-    onSearchKeyDown = (e: React.KeyboardEvent) => {
-        switch (e.key) {
-            case 'Enter':
-                this.setKey(this._menuOptions.length > 0 && this._menuValue.length > 0 ? this._menuOptions[0] : this._menuValue);
-                break;
-            case 'Escape':
-                this.toggleColumnMenu();
-                break;
-        }
-    };
-
-    @action
-    setKey = (key: string, defaultVal?: any) => {
-        if (this._makeNewColumn) {
-            this.props.addColumn(this.props.columnIndex, key, defaultVal);
-        } else {
-            this.props.changeColumnKey(this.props.columnIndex, key, defaultVal);
-        }
-        this.toggleColumnMenu();
-    };
-
-    @action
-    updateKeySearch = (e: React.ChangeEvent<HTMLInputElement>) => {
-        this._menuValue = e.target.value;
-        this._menuOptions = this.props.possibleKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
-    };
-
     // @action
     // onPointerDown = (e: React.PointerEvent) => {
     //     e.stopPropagation();
@@ -196,36 +44,6 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
     //     setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction);
     // };
 
-    @action
-    toggleColumnMenu = (newCol?: boolean) => {
-        this._makeNewColumn = false;
-        if (this._menuVisible) {
-            this._menuVisible = false;
-        } else {
-            this._filterVisible = false;
-            this._menuVisible = true;
-            this._menuValue = '';
-            this._menuOptions = this.props.possibleKeys;
-            this._makeNewField = false;
-            this._newFieldWarning = '';
-            this._makeNewField = false;
-            if (newCol) {
-                this._makeNewColumn = true;
-            }
-        }
-    };
-
-    @action
-    toggleFilterMenu = () => {
-        console.log(this._filterVisible);
-        if (this._filterVisible) {
-            this._filterVisible = false;
-        } else {
-            this._filterVisible = true;
-            this._menuVisible = false;
-        }
-    };
-
     render() {
         return (
             <div className="schema-column-header" style={{ width: this.props.columnWidths[this.props.columnIndex] }}>
@@ -236,17 +54,10 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
                     <div
                         className="schema-header-button"
                         onPointerDown={e => {
-                            this.toggleColumnMenu();
+                            this.props.toggleColumnMenu(this.props.columnIndex, false);
                         }}>
                         <FontAwesomeIcon icon="pencil-alt" />
                     </div>
-                    <div
-                        className="schema-header-button"
-                        onPointerDown={e => {
-                            this.toggleColumnMenu(true);
-                        }}>
-                        <FontAwesomeIcon icon="plus" />
-                    </div>
                     <div
                         className="schema-header-button"
                         onPointerDown={e => {
@@ -257,15 +68,9 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
                     <div className="schema-header-button" onPointerDown={this.sortClicked} style={this.props.sortField == this.fieldKey ? { backgroundColor: Colors.MEDIUM_BLUE } : {}}>
                         <FontAwesomeIcon icon="caret-right" style={this.props.sortField == this.fieldKey ? { transform: `rotate(${this.props.sortDesc ? '270deg' : '90deg'})` } : {}} />
                     </div>
-                    <div className="schema-header-button" onPointerDown={e => this.toggleFilterMenu()}>
-                        <FontAwesomeIcon icon="filter" />
-                    </div>
                 </div>
 
                 <div className="schema-column-resizer right" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex, false)}></div>
-
-                {this._menuVisible && this.renderColumnMenu}
-                {this._filterVisible && this.columnFilterMenu}
             </div>
         );
     }
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 0f832e7c4..43b7da544 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -1,20 +1,14 @@
 import React = require('react');
 import { observer } from 'mobx-react';
-import { Doc, DocListCast, Field } from '../../../../fields/Doc';
-import './CollectionSchemaView.scss';
-import { type } from 'jquery';
-import { action } from 'mobx';
-import { ComputedField } from '../../../../fields/ScriptField';
-import { FieldValue } from '../../../../fields/Types';
-import { CompileScript } from '../../../util/Scripting';
+import { Doc, Field } from '../../../../fields/Doc';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../../Utils';
+import { Transform } from '../../../util/Transform';
 import { EditableView } from '../../EditableView';
-import { MAX_ROW_HEIGHT } from '../../global/globalCssVariables.scss';
 import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { KeyValueBox } from '../../nodes/KeyValueBox';
-import { returnEmptyFilter, returnEmptyDoclist, returnFalse, emptyFunction, returnZero } from '../../../../Utils';
 import { DefaultStyleProvider } from '../../StyleProvider';
-import { Transform } from '../../../util/Transform';
 import { CollectionSchemaView } from './CollectionSchemaView';
+import './CollectionSchemaView.scss';
 
 export interface SchemaTableCellProps {
     Document: Doc;
@@ -28,7 +22,6 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     render() {
         const props: FieldViewProps = {
             Document: this.props.Document,
-            // DataDoc: this.props.doc,
             docFilters: returnEmptyFilter,
             docRangeFilters: returnEmptyFilter,
             searchFilterDocs: returnEmptyDoclist,
@@ -56,8 +49,6 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
 
         return (
             <div className="schema-table-cell" style={{ width: this.props.columnWidth, pointerEvents: this.props.isRowActive() ? 'all' : 'none' }}>
-                {/* {Field.toString(this.props.Document[this.props.fieldKey] as Field)} */}
-                {/* <EditableView contents={Field.toString(this.props.Document[this.props.fieldKey] as Field)} GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)} SetValue={(value: string) => true} /> */}
                 <EditableView
                     contents={<FieldView {...props} />}
                     height={'auto'}
-- 
cgit v1.2.3-70-g09d2


From c68e751531f972fcf201089f26e69627cfe4fe3c Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Tue, 14 Mar 2023 19:31:52 -0400
Subject: single filter through search added

---
 .../collectionSchema/CollectionSchemaView.scss     |  35 ++-
 .../collectionSchema/CollectionSchemaView.tsx      | 323 ++++++++++++++-------
 .../collectionSchema/SchemaColumnHeader.tsx        |  31 +-
 3 files changed, 258 insertions(+), 131 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 931645857..5eb5cc86d 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -9,7 +9,8 @@
     .schema-table {
         background-color: $white;
 
-        .schema-column-menu {
+        .schema-column-menu,
+        .schema-filter-menu {
             background: $light-gray;
             position: absolute;
             min-width: 200px;
@@ -83,6 +84,11 @@
         .schema-header-row {
             justify-content: flex-end;
 
+            .row-menu {
+                display: flex;
+                justify-content: flex-end;
+            }
+
             .schema-column-header {
                 font-weight: bold;
                 display: flex;
@@ -112,10 +118,12 @@
                 }
 
                 .schema-column-resizer.right {
+                    margin-left: 5px;
                     align-self: flex-end;
                 }
 
                 .schema-column-resizer.left {
+                    margin-right: 5px;
                     align-self: flex-start;
                 }
             }
@@ -139,6 +147,10 @@
     overflow: hidden;
 }
 
+.schema-header-row {
+    background-color: $light-gray;
+}
+
 .schema-header-row,
 .schema-row {
     display: flex;
@@ -163,8 +175,8 @@
     .row-menu {
         display: flex;
         flex-direction: row;
-        justify-content: center;
         min-width: 50px;
+        justify-content: flex-end;
     }
 
     .row-cells {
@@ -176,9 +188,22 @@
 
 .schema-row-button,
 .schema-header-button {
-    width: 20px;
-    height: 20px;
-    border-radius: 100%;
+    color: $dark-gray;
+    margin: 3px;
+    cursor: pointer;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+
+    svg {
+        width: 15px;
+    }
+}
+
+.schema-sort-button {
+    width: 17px;
+    height: 17px;
+    border-radius: 30%;
     background-color: $dark-gray;
     color: white;
     margin: 3px;
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index fd7790c4b..e1c2d989f 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,7 +1,7 @@
 import React = require('react');
 import { action, computed, observable, ObservableMap, ObservableSet, untracked } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
+import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { RichTextField } from '../../../../fields/RichTextField';
@@ -17,7 +17,7 @@ import { undoBatch } from '../../../util/UndoManager';
 import { ContextMenu } from '../../ContextMenu';
 import { ContextMenuProps } from '../../ContextMenuItem';
 import { EditableView } from '../../EditableView';
-import { DocComponentView, DocFocusOptions, DocumentView, ViewAdjustment } from '../../nodes/DocumentView';
+import { DocComponentView, DocFocusOptions, DocumentView } from '../../nodes/DocumentView';
 import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
 import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
@@ -46,7 +46,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _previewRef: HTMLDivElement | null = null;
     private _makeNewColumn: boolean = false;
 
-    public static _rowHeight: number = 50;
+    public static _rowHeight: number = 40;
     public static _minColWidth: number = 150;
     public static _rowMenuWidth: number = 100;
     public static _previewDividerWidth: number = 4;
@@ -63,6 +63,8 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _newFieldDefault: any = 0;
     @observable _newFieldType: ColumnType = ColumnType.Number;
     @observable _menuValue: string = '';
+    @observable _filterColumnIndex: number | undefined;
+    @observable _filterValue: string = '';
 
     get documentKeys() {
         const docs = this.childDocs;
@@ -533,20 +535,18 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     focusDocument = (doc: Doc, options: DocFocusOptions) => {
         Doc.BrushDoc(doc);
-        let focusSpeed = 0;
+
         const found = this._mainCont && Array.from(this._mainCont.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) {
-                smoothScroll((focusSpeed = options.zoomTime ?? 500), this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc);
+                let focusSpeed = options.zoomTime ?? 500;
+                smoothScroll(focusSpeed, this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc);
+                return focusSpeed;
             }
         }
-        const endFocus = async (moved: boolean) => options?.afterFocus?.(moved) ?? ViewAdjustment.doNothing;
-        this.props.focus(this.rootDoc, {
-            ...options,
-            afterFocus: (didFocus: boolean) => new Promise<ViewAdjustment>(res => setTimeout(async () => res(await endFocus(didFocus)), focusSpeed)),
-        });
+        return undefined;
     };
 
     isChildContentActive = () =>
@@ -574,7 +574,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                 this._menuOptions.length > 0 && this._menuValue.length > 0 ? this.setKey(this._menuOptions[0]) : action(() => (this._makeNewField = true))();
                 break;
             case 'Escape':
-                this.toggleColumnMenu(this._columnMenuIndex);
+                this.closeColumnMenu();
                 break;
         }
     };
@@ -586,25 +586,63 @@ export class CollectionSchemaView extends CollectionSubView() {
         } else {
             this.changeColumnKey(this._columnMenuIndex!, key, defaultVal);
         }
-        this.toggleColumnMenu(this._columnMenuIndex);
+        this.closeColumnMenu();
     };
 
     @action
-    toggleColumnMenu = (index: number | undefined, newCol?: boolean) => {
+    openColumnMenu = (index: number, newCol: boolean) => {
         this._makeNewColumn = false;
-        if (this._columnMenuIndex !== undefined && index === this._columnMenuIndex) {
-            this._columnMenuIndex = undefined;
-        } else {
-            this._columnMenuIndex = index;
-            this._menuValue = '';
-            this._menuOptions = this.documentKeys;
-            this._makeNewField = false;
-            this._newFieldWarning = '';
-            this._makeNewField = false;
-            if (newCol) {
-                this._makeNewColumn = true;
-            }
-        }
+        this._columnMenuIndex = index;
+        this._menuValue = '';
+        this._menuOptions = this.documentKeys;
+        this._makeNewField = false;
+        this._newFieldWarning = '';
+        this._makeNewField = false;
+        this._makeNewColumn = newCol;
+    };
+
+    @action
+    closeColumnMenu = () => {
+        this._columnMenuIndex = undefined;
+    };
+
+    @action
+    openFilterMenu = (index: number) => {
+        this._filterColumnIndex = index;
+        this._filterValue = this.getFieldFilters(this.columnKeys[this._filterColumnIndex!]).map(filter => filter.split(':')[1])[0];
+    };
+
+    @action
+    closeFilterMenu = () => {
+        this._filterColumnIndex = undefined;
+    };
+
+    openContextMenu = (x: number, y: number, index: number) => {
+        this.closeColumnMenu();
+        this.closeFilterMenu();
+        ContextMenu.Instance.clearItems();
+        ContextMenu.Instance.addItem({
+            description: 'Change field',
+            event: () => {
+                this.openColumnMenu(index, false);
+            },
+            icon: 'pencil-alt',
+        });
+        ContextMenu.Instance.addItem({
+            description: 'Filter field',
+            event: () => {
+                this.openFilterMenu(index);
+            },
+            icon: 'filter',
+        });
+        ContextMenu.Instance.addItem({
+            description: 'Delete column',
+            event: () => {
+                this.removeColumn(index);
+            },
+            icon: 'trash',
+        });
+        ContextMenu.Instance.displayMenu(x, y, undefined, false);
     };
 
     @action
@@ -613,92 +651,156 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._menuOptions = this.documentKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
     };
 
-    @computed get renderColumnMenu() {
-        const x = this.displayColumnWidths.reduce((total, curr, index) => total + (index < this._columnMenuIndex! ? curr : 0), CollectionSchemaView._rowMenuWidth);
+    getFieldFilters = (field: string) => {
+        return StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field);
+    };
+
+    removeFieldFilters = (field: string) => {
+        this.getFieldFilters(field).forEach(filter => {
+            Doc.setDocFilter(this.Document, field, filter.split(':')[1], 'remove');
+        });
+    };
+
+    onFilterKeyDown = (e: React.KeyboardEvent) => {
+        switch (e.key) {
+            case 'Enter':
+                if (this._filterValue !== '') {
+                    Doc.setDocFilter(this.Document, this.columnKeys[this._filterColumnIndex!], this._filterValue, 'check', false, undefined, false);
+                } else {
+                    this.removeFieldFilters(this.columnKeys[this._filterColumnIndex!]);
+                }
+                this.closeFilterMenu();
+                break;
+            case 'Escape':
+                this.closeFilterMenu();
+                break;
+        }
+    };
+
+    @action
+    updateFilterSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
+        this._filterValue = e.target.value;
+    };
+
+    @computed get newFieldMenu() {
         return (
-            <div className="schema-column-menu" style={{ left: x }}>
-                <input className="schema-key-search-input" type="text" value={this._menuValue} onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
-                {this._makeNewField ? (
-                    <div className="schema-new-key-options">
-                        <div className="schema-key-type-option">
-                            <input
-                                type="radio"
-                                name="newFieldType"
-                                id=""
-                                checked={this._newFieldType == ColumnType.Number}
-                                onChange={action(() => {
-                                    this._newFieldType = ColumnType.Number;
-                                    this._newFieldDefault = 0;
-                                })}
-                            />
-                            number
-                        </div>
-                        <div className="schema-key-type-option">
-                            <input
-                                type="radio"
-                                name="newFieldType"
-                                id=""
-                                checked={this._newFieldType == ColumnType.Boolean}
-                                onChange={action(() => {
-                                    this._newFieldType = ColumnType.Boolean;
-                                    this._newFieldDefault = false;
-                                })}
-                            />
-                            boolean
-                        </div>
-                        <div className="schema-key-type-option">
-                            <input
-                                type="radio"
-                                name="newFieldType"
-                                id=""
-                                checked={this._newFieldType == ColumnType.String}
-                                onChange={action(() => {
-                                    this._newFieldType = ColumnType.String;
-                                    this._newFieldDefault = '';
-                                })}
-                            />
-                            string
-                        </div>
-                        <div className="schema-key-default-val">value: {this.fieldDefaultInput}</div>
-                        <div className="schema-key-warning">{this._newFieldWarning}</div>
-                        <div
-                            className="schema-column-menu-button"
-                            onPointerDown={action(e => {
-                                if (this.documentKeys.includes(this._menuValue)) {
-                                    this._newFieldWarning = 'Field already exists';
-                                } else if (this._menuValue.length === 0) {
-                                    this._newFieldWarning = 'Field cannot be an empty string';
-                                } else {
-                                    this.setKey(this._menuValue, this._newFieldDefault);
-                                }
-                            })}>
-                            done
-                        </div>
-                    </div>
-                ) : (
-                    <div className="schema-key-search">
+            <div className="schema-new-key-options">
+                <div className="schema-key-type-option">
+                    <input
+                        type="radio"
+                        name="newFieldType"
+                        id=""
+                        checked={this._newFieldType == ColumnType.Number}
+                        onChange={action(() => {
+                            this._newFieldType = ColumnType.Number;
+                            this._newFieldDefault = 0;
+                        })}
+                    />
+                    number
+                </div>
+                <div className="schema-key-type-option">
+                    <input
+                        type="radio"
+                        name="newFieldType"
+                        id=""
+                        checked={this._newFieldType == ColumnType.Boolean}
+                        onChange={action(() => {
+                            this._newFieldType = ColumnType.Boolean;
+                            this._newFieldDefault = false;
+                        })}
+                    />
+                    boolean
+                </div>
+                <div className="schema-key-type-option">
+                    <input
+                        type="radio"
+                        name="newFieldType"
+                        id=""
+                        checked={this._newFieldType == ColumnType.String}
+                        onChange={action(() => {
+                            this._newFieldType = ColumnType.String;
+                            this._newFieldDefault = '';
+                        })}
+                    />
+                    string
+                </div>
+                <div className="schema-key-default-val">value: {this.fieldDefaultInput}</div>
+                <div className="schema-key-warning">{this._newFieldWarning}</div>
+                <div
+                    className="schema-column-menu-button"
+                    onPointerDown={action(e => {
+                        if (this.documentKeys.includes(this._menuValue)) {
+                            this._newFieldWarning = 'Field already exists';
+                        } else if (this._menuValue.length === 0) {
+                            this._newFieldWarning = 'Field cannot be an empty string';
+                        } else {
+                            this.setKey(this._menuValue, this._newFieldDefault);
+                        }
+                    })}>
+                    done
+                </div>
+            </div>
+        );
+    }
+
+    @computed get keysDropdown() {
+        return (
+            <div className="schema-key-search">
+                <div
+                    className="schema-column-menu-button"
+                    onPointerDown={action(e => {
+                        e.stopPropagation();
+                        this._makeNewField = true;
+                    })}>
+                    + new field
+                </div>
+                <div className="schema-key-list">
+                    {this._menuOptions.map(key => (
                         <div
-                            className="schema-column-menu-button"
-                            onPointerDown={action(e => {
+                            className="schema-key-search-result"
+                            onPointerDown={e => {
                                 e.stopPropagation();
-                                this._makeNewField = true;
-                            })}>
-                            + new field
+                                this.setKey(key);
+                            }}>
+                            {key}
                         </div>
-                        <div className="schema-key-list">
-                            {this._menuOptions.map(key => (
-                                <div
-                                    className="schema-key-search-result"
-                                    onPointerDown={e => {
-                                        e.stopPropagation();
-                                        this.setKey(key);
-                                    }}>
-                                    {key}
-                                </div>
-                            ))}
-                        </div>
-                    </div>
-                )}
+                    ))}
+                </div>
+            </div>
+        );
+    }
+
+    @computed get renderColumnMenu() {
+        const x = this._columnMenuIndex! == -1 ? 0 : this.displayColumnWidths.reduce((total, curr, index) => total + (index < this._columnMenuIndex! ? curr : 0), CollectionSchemaView._rowMenuWidth);
+        return (
+            <div className="schema-column-menu" style={{ left: x, minWidth: CollectionSchemaView._minColWidth }}>
+                <input className="schema-key-search-input" type="text" value={this._menuValue} onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
+                {this._makeNewField ? this.newFieldMenu : this.keysDropdown}
+                <div
+                    className="schema-column-menu-button"
+                    onPointerDown={action(e => {
+                        e.stopPropagation();
+                        this.closeColumnMenu();
+                    })}>
+                    cancel
+                </div>
+            </div>
+        );
+    }
+
+    @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()} />
+                <div
+                    className="schema-column-menu-button"
+                    onPointerDown={action(e => {
+                        e.stopPropagation();
+                        this.closeFilterMenu();
+                    })}>
+                    cancel
+                </div>
             </div>
         );
     }
@@ -722,7 +824,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                             <div
                                 className="schema-header-button"
                                 onPointerDown={e => {
-                                    this.toggleColumnMenu(-1, true);
+                                    this.openColumnMenu(-1, true);
                                 }}>
                                 <FontAwesomeIcon icon="plus" />
                             </div>
@@ -739,12 +841,13 @@ export class CollectionSchemaView extends CollectionSubView() {
                                     setSort={this.setSort}
                                     removeColumn={this.removeColumn}
                                     resizeColumn={this.startResize}
-                                    toggleColumnMenu={this.toggleColumnMenu}
+                                    openContextMenu={this.openContextMenu}
                                 />
                             );
                         })}
                     </div>
                     {this._columnMenuIndex !== undefined && this.renderColumnMenu}
+                    {this._filterColumnIndex !== undefined && this.renderFilterMenu}
                     <div className="schema-table-content" onPointerDown={e => e.stopPropagation()}>
                         {this.childDocs.map((doc: Doc, index: number) => {
                             const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.DataDoc;
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index ba63b352b..42626697a 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -5,7 +5,17 @@ import { observer } from 'mobx-react';
 import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
 import './CollectionSchemaView.scss';
 import { ColumnType } from './CollectionSchemaView';
-import { Colors } from 'browndash-components';
+import { IconButton } from 'browndash-components';
+import { Colors } from '../../global/globalEnums';
+import { ContextMenu } from '../../ContextMenu';
+import { Doc, DocListCast } from '../../../../fields/Doc';
+import { Id } from '../../../../fields/FieldSymbols';
+import { RichTextField } from '../../../../fields/RichTextField';
+import { StrCast } from '../../../../fields/Types';
+import { ImageField } from '../../../../fields/URLField';
+import { DocUtils, Docs } from '../../../documents/Documents';
+import { ContextMenuProps } from '../../ContextMenuItem';
+import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
 
 export interface SchemaColumnHeaderProps {
     columnKeys: string[];
@@ -16,8 +26,8 @@ export interface SchemaColumnHeaderProps {
     setSort: (field: string, desc: boolean) => void;
     removeColumn: (index: number) => void;
     resizeColumn: (e: any, index: number, left: boolean) => void;
-    toggleColumnMenu: (index: number | undefined, newCol?: boolean) => void;
     // dragColumn: (e: any, index: number) => boolean;
+    openContextMenu: (x: number, y: number, index: number) => void;
 }
 
 @observer
@@ -51,21 +61,10 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
                 <div className="schema-column-title">{this.fieldKey}</div>
 
                 <div className="schema-header-menu">
-                    <div
-                        className="schema-header-button"
-                        onPointerDown={e => {
-                            this.props.toggleColumnMenu(this.props.columnIndex, false);
-                        }}>
-                        <FontAwesomeIcon icon="pencil-alt" />
+                    <div className="schema-header-button" onPointerDown={e => this.props.openContextMenu(e.clientX, e.clientY, this.props.columnIndex)}>
+                        <FontAwesomeIcon icon="ellipsis-h" />
                     </div>
-                    <div
-                        className="schema-header-button"
-                        onPointerDown={e => {
-                            this.props.removeColumn(this.props.columnIndex);
-                        }}>
-                        <FontAwesomeIcon icon="trash" />
-                    </div>
-                    <div className="schema-header-button" onPointerDown={this.sortClicked} style={this.props.sortField == this.fieldKey ? { backgroundColor: Colors.MEDIUM_BLUE } : {}}>
+                    <div className="schema-sort-button" onPointerDown={this.sortClicked} style={this.props.sortField == this.fieldKey ? { backgroundColor: Colors.MEDIUM_BLUE } : {}}>
                         <FontAwesomeIcon icon="caret-right" style={this.props.sortField == this.fieldKey ? { transform: `rotate(${this.props.sortDesc ? '270deg' : '90deg'})` } : {}} />
                     </div>
                 </div>
-- 
cgit v1.2.3-70-g09d2


From 61ce7b4d434aff7e642d2af17b8643297f99e4a3 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 15 Mar 2023 18:15:18 -0400
Subject: column drag in progress

---
 src/client/util/DragManager.ts                     |  14 +-
 .../collectionSchema/CollectionSchemaView.scss     | 112 ++++++-------
 .../collectionSchema/CollectionSchemaView.tsx      |  40 +++--
 .../collectionSchema/SchemaColumnHeader.tsx        |  21 ++-
 .../collectionSchema/SchemaTableCell.tsx           |  16 +-
 .../views/nodes/RecordingBox/RecordingView.tsx     | 177 ++++++++++-----------
 6 files changed, 197 insertions(+), 183 deletions(-)

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

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index a56f87075..1b413c73b 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -149,10 +149,14 @@ export namespace DragManager {
         linkDragView: DocumentView;
     }
     export class ColumnDragData {
-        constructor(colKey: SchemaHeaderField) {
-            this.colKey = colKey;
+        // constructor(colKey: SchemaHeaderField) {
+        //     this.colKey = colKey;
+        // }
+        // colKey: SchemaHeaderField;
+        constructor(colIndex: number) {
+            this.colIndex = colIndex;
         }
-        colKey: SchemaHeaderField;
+        colIndex: number;
     }
     // used by PDFs,Text,Image,Video,Web to conditionally (if the drop completes) create a text annotation when dragging the annotate button from the AnchorMenu when a text/region selection has been made.
     // this is pretty clunky and should be rethought out using linkDrag or DocumentDrag
@@ -256,8 +260,8 @@ export namespace DragManager {
     }
 
     // drags a column from a schema view
-    export function StartColumnDrag(ele: HTMLElement, dragData: ColumnDragData, downX: number, downY: number, options?: DragOptions) {
-        StartDrag([ele], dragData, downX, downY, options);
+    export function StartColumnDrag(ele: HTMLElement[], dragData: ColumnDragData, downX: number, downY: number, options?: DragOptions) {
+        StartDrag(ele, dragData, downX, downY, options);
     }
 
     export function SetSnapLines(horizLines: number[], vertLines: number[]) {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 5eb5cc86d..1853fb589 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -8,6 +8,7 @@
 
     .schema-table {
         background-color: $white;
+        cursor: default;
 
         .schema-column-menu,
         .schema-filter-menu {
@@ -80,68 +81,70 @@
                 align-self: center;
             }
         }
+    }
 
-        .schema-header-row {
-            justify-content: flex-end;
+    .schema-preview-divider {
+        height: 100%;
+        background: black;
+        cursor: ew-resize;
+    }
+}
 
-            .row-menu {
-                display: flex;
-                justify-content: flex-end;
-            }
+.schema-header-row {
+    cursor: grab;
+    justify-content: flex-end;
 
-            .schema-column-header {
-                font-weight: bold;
-                display: flex;
-                flex-direction: row;
-                justify-content: space-between;
-                align-items: center;
-                padding: 0;
-                z-index: 1;
-
-                .schema-column-title {
-                    flex-grow: 2;
-                    margin: 5px;
-                }
+    .row-menu {
+        display: flex;
+        justify-content: flex-end;
+    }
+}
 
-                .schema-header-menu {
-                    margin: 5px;
-                }
+.schema-column-header {
+    background-color: $light-gray;
+    font-weight: bold;
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    padding: 0;
+    z-index: 1;
 
-                .schema-column-resizer {
-                    height: 100%;
-                    width: 3px;
-                    cursor: ew-resize;
+    .schema-column-title {
+        flex-grow: 2;
+        margin: 5px;
+    }
 
-                    &:hover {
-                        background-color: $light-blue;
-                    }
-                }
+    .schema-header-menu {
+        margin: 5px;
+    }
 
-                .schema-column-resizer.right {
-                    margin-left: 5px;
-                    align-self: flex-end;
-                }
+    .schema-column-resizer {
+        height: 100%;
+        width: 3px;
+        cursor: ew-resize;
 
-                .schema-column-resizer.left {
-                    margin-right: 5px;
-                    align-self: flex-start;
-                }
-            }
+        &:hover {
+            background-color: $light-blue;
         }
+    }
 
-        .schema-header-menu {
-            display: flex;
-            flex-direction: row;
-        }
+    .schema-column-resizer.right {
+        margin-left: 5px;
+        align-self: flex-end;
     }
 
-    .schema-preview-divider {
-        height: 100%;
-        background: black;
-        cursor: ew-resize;
+    .schema-column-resizer.left {
+        margin-right: 5px;
+        align-self: flex-start;
     }
 }
 
+.schema-header-menu {
+    display: flex;
+    flex-direction: row;
+}
+
 .schema-row-wrapper {
     // max-height: 70px;
     overflow: hidden;
@@ -158,17 +161,18 @@
     height: 100%;
     // max-height: 70px;
     overflow: auto;
+}
 
-    .schema-column-header,
-    .schema-table-cell,
-    .row-menu {
-        border: 1px solid $medium-gray;
-        padding: 5px;
-        overflow: hidden;
-    }
+.schema-column-header,
+.schema-table-cell,
+.row-menu {
+    border: 1px solid $medium-gray;
+    padding: 5px;
+    overflow: hidden;
 }
 
 .schema-row {
+    cursor: default;
     justify-content: flex-end;
     background: white;
 
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index e1c2d989f..b0114a226 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -54,6 +54,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _lastSelectedRow: number | undefined;
     @observable _selectedDocs: ObservableSet = new ObservableSet<Doc>();
     @observable _rowEles: ObservableMap = new ObservableMap<Doc, HTMLDivElement>();
+    @observable _colEles: HTMLDivElement[] = [];
     @observable _isDragging: boolean = false;
     @observable _displayColumnWidths: number[] | undefined;
     @observable _columnMenuIndex: number | undefined;
@@ -301,29 +302,32 @@ export class CollectionSchemaView extends CollectionSubView() {
         this.layoutDoc.columnWidths = new List<number>(currWidths);
     };
 
-    // @action
-    // dragColumn = (e: any, index: number) => {
-    //     e.stopPropagation();
-    //     e.preventDefault();
-    //     const rect = e.target.getBoundingClientRect();
-    //     if (e.clientX < rect.x) {
-    //         if (index < 1) return true;
-    //         this.swapColumns(index - 1, index);
-    //         return true;
-    //     }
-    //     if (e.clientX > rect.x + rect.width) {
-    //         if (index === this.columnKeys.length) return true;
-    //         this.swapColumns(index, index + 1);
-    //         return true;
-    //     }
-    //     return false;
-    // };
+    @action
+    dragColumn = (e: PointerEvent, index: number) => {
+        const dragData = new DragManager.ColumnDragData(index);
+        const dragEles = [this._colEles[index]];
+        this.childDocs.forEach(doc => {
+            dragEles.push(this._rowEles.get(doc).children[1].children[index]);
+        });
+        DragManager.StartColumnDrag(dragEles, dragData, e.x, e.y);
+
+        return true;
+    };
 
     @action
     addRowRef = (doc: Doc, ref: HTMLDivElement) => {
         this._rowEles.set(doc, ref);
     };
 
+    @action
+    setColRef = (index: number, ref: HTMLDivElement) => {
+        if (this._colEles.length <= index) {
+            this._colEles.push(ref);
+        } else {
+            this._colEles[index] = ref;
+        }
+    };
+
     @action
     addDocToSelection = (doc: Doc, extendSelection: boolean, index: number) => {
         this._selectedDocs.add(doc);
@@ -842,6 +846,8 @@ export class CollectionSchemaView extends CollectionSubView() {
                                     removeColumn={this.removeColumn}
                                     resizeColumn={this.startResize}
                                     openContextMenu={this.openContextMenu}
+                                    dragColumn={this.dragColumn}
+                                    setColRef={this.setColRef}
                                 />
                             );
                         })}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 42626697a..e648356f4 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -26,8 +26,9 @@ export interface SchemaColumnHeaderProps {
     setSort: (field: string, desc: boolean) => void;
     removeColumn: (index: number) => void;
     resizeColumn: (e: any, index: number, left: boolean) => void;
-    // dragColumn: (e: any, index: number) => boolean;
+    dragColumn: (e: any, index: number) => boolean;
     openContextMenu: (x: number, y: number, index: number) => void;
+    setColRef: (index: number, ref: HTMLDivElement) => void;
 }
 
 @observer
@@ -47,16 +48,20 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
         }
     };
 
-    // @action
-    // onPointerDown = (e: React.PointerEvent) => {
-    //     e.stopPropagation();
-
-    //     setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction);
-    // };
+    @action
+    onPointerDown = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction);
+    };
 
     render() {
         return (
-            <div className="schema-column-header" style={{ width: this.props.columnWidths[this.props.columnIndex] }}>
+            <div
+                className="schema-column-header"
+                style={{ width: this.props.columnWidths[this.props.columnIndex] }}
+                onPointerDown={this.onPointerDown}
+                ref={(col: HTMLDivElement | null) => {
+                    col && this.props.setColRef(this.props.columnIndex, col);
+                }}>
                 <div className="schema-column-resizer left" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex, true)}></div>
                 <div className="schema-column-title">{this.fieldKey}</div>
 
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 43b7da544..91b292b28 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -48,13 +48,15 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         };
 
         return (
-            <div className="schema-table-cell" style={{ width: this.props.columnWidth, pointerEvents: this.props.isRowActive() ? 'all' : 'none' }}>
-                <EditableView
-                    contents={<FieldView {...props} />}
-                    height={'auto'}
-                    GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
-                    SetValue={(value: string) => KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value)}
-                />
+            <div className="schema-table-cell" style={{ width: this.props.columnWidth }}>
+                <div className="schemacell-edit-wrapper" style={{ cursor: this.props.isRowActive() ? 'text' : 'default' }}>
+                    <EditableView
+                        contents={<FieldView {...props} />}
+                        GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
+                        SetValue={(value: string) => KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value)}
+                        editing={this.props.isRowActive() ? undefined : false}
+                    />
+                </div>
             </div>
         );
     }
diff --git a/src/client/views/nodes/RecordingBox/RecordingView.tsx b/src/client/views/nodes/RecordingBox/RecordingView.tsx
index ec5917b9e..6efe62e0b 100644
--- a/src/client/views/nodes/RecordingBox/RecordingView.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingView.tsx
@@ -1,32 +1,31 @@
 import * as React from 'react';
-import "./RecordingView.scss";
-import { useEffect, useRef, useState } from "react";
-import { ProgressBar } from "./ProgressBar"
+import './RecordingView.scss';
+import { useEffect, useRef, useState } from 'react';
+import { ProgressBar } from './ProgressBar';
 import { MdBackspace } from 'react-icons/md';
 import { FaCheckCircle } from 'react-icons/fa';
-import { IconContext } from "react-icons";
+import { IconContext } from 'react-icons';
 import { Networking } from '../../../Network';
 import { Upload } from '../../../../server/SharedMediaTypes';
 import { returnFalse, returnTrue, setupMoveUpEvents } from '../../../../Utils';
 import { Presentation, TrackMovements } from '../../../util/TrackMovements';
 
 export interface MediaSegment {
-    videoChunks: any[],
-    endTime: number,
-    startTime: number,
-    presentation?: Presentation,
+    videoChunks: any[];
+    endTime: number;
+    startTime: number;
+    presentation?: Presentation;
 }
 
 interface IRecordingViewProps {
-    setResult: (info: Upload.AccessPathInfo, presentation?: Presentation) => void
-    setDuration: (seconds: number) => void
-    id: string
+    setResult: (info: Upload.AccessPathInfo, presentation?: Presentation) => void;
+    setDuration: (seconds: number) => void;
+    id: string;
 }
 
 const MAXTIME = 100000;
 
 export function RecordingView(props: IRecordingViewProps) {
-
     const [recording, setRecording] = useState(false);
     const recordingTimerRef = useRef<number>(0);
     const [recordingTimer, setRecordingTimer] = useState(0); // unit is 0.01 second
@@ -46,19 +45,16 @@ export function RecordingView(props: IRecordingViewProps) {
     const [finished, setFinished] = useState<boolean>(false);
     const [trackScreen, setTrackScreen] = useState<boolean>(false);
 
-
-
     const DEFAULT_MEDIA_CONSTRAINTS = {
         video: {
             width: 1280,
             height: 720,
-
         },
         audio: {
             echoCancellation: true,
             noiseSuppression: true,
-            sampleRate: 44100
-        }
+            sampleRate: 44100,
+        },
     };
 
     useEffect(() => {
@@ -71,12 +67,11 @@ export function RecordingView(props: IRecordingViewProps) {
                 const videoFiles = videos.map((vid, i) => new File(vid.videoChunks, `segvideo${i}.mkv`, { type: vid.videoChunks[0].type, lastModified: Date.now() }));
 
                 // upload the segments to the server and get their server access paths
-                const serverPaths: string[] = (await Networking.UploadFilesToServer(videoFiles))
-                    .map(res => (res.result instanceof Error) ? '' : res.result.accessPaths.agnostic.server)
+                const serverPaths: string[] = (await Networking.UploadFilesToServer(videoFiles)).map(res => (res.result instanceof Error ? '' : res.result.accessPaths.agnostic.server));
 
                 // concat the segments together using post call
                 const result: Upload.AccessPathInfo | Error = await Networking.PostToServer('/concatVideos', serverPaths);
-                !(result instanceof Error) ? props.setResult(result, concatPres || undefined) : console.error("video conversion failed");
+                !(result instanceof Error) ? props.setResult(result, concatPres || undefined) : console.error('video conversion failed');
             })();
         }
     }, [videos]);
@@ -87,7 +82,9 @@ export function RecordingView(props: IRecordingViewProps) {
     }, [finished]);
 
     // check if the browser supports media devices on first load
-    useEffect(() => { if (!navigator.mediaDevices) alert('This browser does not support getUserMedia.'); }, []);
+    useEffect(() => {
+        if (!navigator.mediaDevices) alert('This browser does not support getUserMedia.');
+    }, []);
 
     useEffect(() => {
         let interval: any = null;
@@ -102,24 +99,24 @@ export function RecordingView(props: IRecordingViewProps) {
     }, [recording]);
 
     useEffect(() => {
-        setVideoProgressHelper(recordingTimer)
+        setVideoProgressHelper(recordingTimer);
         recordingTimerRef.current = recordingTimer;
     }, [recordingTimer]);
 
     const setVideoProgressHelper = (progress: number) => {
         const newProgress = (progress / MAXTIME) * 100;
         setProgress(newProgress);
-    }
+    };
 
     const startShowingStream = async (mediaConstraints = DEFAULT_MEDIA_CONSTRAINTS) => {
         const stream = await navigator.mediaDevices.getUserMedia(mediaConstraints);
 
-        videoElementRef.current!.src = "";
+        videoElementRef.current!.src = '';
         videoElementRef.current!.srcObject = stream;
         videoElementRef.current!.muted = true;
 
         return stream;
-    }
+    };
 
     const record = async () => {
         // don't need to start a new stream every time we start recording a new segment
@@ -145,29 +142,28 @@ export function RecordingView(props: IRecordingViewProps) {
                 const nextVideo = {
                     videoChunks,
                     endTime: recordingTimerRef.current,
-                    startTime: videos?.lastElement()?.endTime || 0
+                    startTime: videos?.lastElement()?.endTime || 0,
                 };
 
                 // depending on if a presenation exists, add it to the video
                 const presentation = TrackMovements.Instance.yieldPresentation();
-                setVideos(videos => [...videos, (presentation != null && trackScreen) ? { ...nextVideo, presentation } : nextVideo]);
+                setVideos(videos => [...videos, presentation != null && trackScreen ? { ...nextVideo, presentation } : nextVideo]);
             }
 
             // reset the temporary chunks
             videoChunks = [];
             setRecording(false);
-        }
+        };
 
         videoRecorder.current.start(200);
-    }
-
+    };
 
     // if this is called, then we're done recording all the segments
     const finish = (e: React.PointerEvent) => {
         e.stopPropagation();
 
         // call stop on the video recorder if active
-        videoRecorder.current?.state !== "inactive" && videoRecorder.current?.stop();
+        videoRecorder.current?.state !== 'inactive' && videoRecorder.current?.stop();
 
         // end the streams (audio/video) to remove recording icon
         const stream = videoElementRef.current!.srcObject;
@@ -178,94 +174,91 @@ export function RecordingView(props: IRecordingViewProps) {
 
         // this will call upon progessbar to update videos to be in the correct order
         setFinished(true);
-    }
+    };
 
     const pause = (e: React.PointerEvent) => {
         e.stopPropagation();
         // if recording, then this is just a new segment
-        videoRecorder.current?.state === "recording" && videoRecorder.current.stop();
-    }
+        videoRecorder.current?.state === 'recording' && videoRecorder.current.stop();
+    };
 
     const start = (e: React.PointerEvent) => {
-        setupMoveUpEvents({}, e, returnTrue, returnFalse, e => {
-            // start recording if not already recording
-            if (!videoRecorder.current || videoRecorder.current.state === "inactive") record();
-
-            return true; // cancels propagation to documentView to avoid selecting it.
-        }, false, false);
-    }
+        setupMoveUpEvents(
+            {},
+            e,
+            returnTrue,
+            returnFalse,
+            e => {
+                // start recording if not already recording
+                if (!videoRecorder.current || videoRecorder.current.state === 'inactive') record();
+
+                return true; // cancels propagation to documentView to avoid selecting it.
+            },
+            false,
+            false
+        );
+    };
 
     const undoPrevious = (e: React.PointerEvent) => {
         e.stopPropagation();
         setDoUndo(prev => !prev);
-    }
+    };
 
-    const handleOnTimeUpdate = () => { playing && setVideoProgressHelper(videoElementRef.current!.currentTime); };
+    const handleOnTimeUpdate = () => {
+        playing && setVideoProgressHelper(videoElementRef.current!.currentTime);
+    };
 
     const millisecondToMinuteSecond = (milliseconds: number) => {
         const toTwoDigit = (digit: number) => {
-            return String(digit).length == 1 ? "0" + digit : digit
-        }
+            return String(digit).length == 1 ? '0' + digit : digit;
+        };
         const minutes = Math.floor((milliseconds % (1000 * 60 * 60)) / (1000 * 60));
         const seconds = Math.floor((milliseconds % (1000 * 60)) / 1000);
-        return toTwoDigit(minutes) + " : " + toTwoDigit(seconds);
-    }
+        return toTwoDigit(minutes) + ' : ' + toTwoDigit(seconds);
+    };
 
     return (
         <div className="recording-container">
             <div className="video-wrapper">
-                <video id={`video-${props.id}`}
-                    autoPlay
-                    muted
-                    onTimeUpdate={() => handleOnTimeUpdate()}
-                    ref={videoElementRef}
-                />
+                <video id={`video-${props.id}`} autoPlay muted onTimeUpdate={() => handleOnTimeUpdate()} ref={videoElementRef} />
                 <div className="recording-sign">
                     <span className="dot" />
                     <p className="timer">{millisecondToMinuteSecond(recordingTimer * 10)}</p>
                 </div>
                 <div className="controls">
-
                     <div className="controls-inner-container">
-                        <div className="record-button-wrapper">
-                            {recording ?
-                                <button className="stop-button" onPointerDown={pause} /> :
-                                <button className="record-button" onPointerDown={start} />
-                            }
-                        </div>
-
-                        {!recording && (videos.length > 0 ?
-
-                            <div className="options-wrapper video-edit-wrapper">
-                                <IconContext.Provider value={{ color: "grey", className: "video-edit-buttons", style: { display: canUndo ? 'inherit' : 'none' } }}>
-                                    <MdBackspace onPointerDown={undoPrevious} />
-                                </IconContext.Provider>
-                                <IconContext.Provider value={{ color: "#cc1c08", className: "video-edit-buttons" }}>
-                                    <FaCheckCircle onPointerDown={finish} />
-                                </IconContext.Provider>
-                            </div>
-
-                            : <div className="options-wrapper track-screen-wrapper">
-                                <label className="track-screen">
-                                    <input type="checkbox" checked={trackScreen} onChange={(e) => { setTrackScreen(e.target.checked) }} />
-                                    <span className="checkmark"></span>
-                                    Track Screen
-                                </label>
-                            </div>)}
-
+                        <div className="record-button-wrapper">{recording ? <button className="stop-button" onPointerDown={pause} /> : <button className="record-button" onPointerDown={start} />}</div>
+
+                        {!recording &&
+                            (videos.length > 0 ? (
+                                <div className="options-wrapper video-edit-wrapper">
+                                    <IconContext.Provider value={{ color: 'grey', className: 'video-edit-buttons', style: { display: canUndo ? 'inherit' : 'none' } }}>
+                                        <MdBackspace onPointerDown={undoPrevious} />
+                                    </IconContext.Provider>
+                                    <IconContext.Provider value={{ color: '#cc1c08', className: 'video-edit-buttons' }}>
+                                        <FaCheckCircle onPointerDown={finish} />
+                                    </IconContext.Provider>
+                                </div>
+                            ) : (
+                                <div className="options-wrapper track-screen-wrapper">
+                                    <label className="track-screen">
+                                        <input
+                                            type="checkbox"
+                                            checked={trackScreen}
+                                            onChange={e => {
+                                                setTrackScreen(e.target.checked);
+                                            }}
+                                        />
+                                        <span className="checkmark"></span>
+                                        Track Screen
+                                    </label>
+                                </div>
+                            ))}
                     </div>
-
                 </div>
 
-                <ProgressBar
-                    videos={videos}
-                    setVideos={setVideos}
-                    orderVideos={orderVideos}
-                    progress={progress}
-                    recording={recording}
-                    doUndo={doUndo}
-                    setCanUndo={setCanUndo}
-                />
+                <ProgressBar videos={videos} setVideos={setVideos} orderVideos={orderVideos} progress={progress} recording={recording} doUndo={doUndo} setCanUndo={setCanUndo} />
             </div>
-        </div>)
-}
\ No newline at end of file
+        </div>
+    );
+}
-- 
cgit v1.2.3-70-g09d2


From 3131630ba45444ca52e1db0df4b1649c1770206a Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 23 Mar 2023 18:03:52 -0400
Subject: updated add/remove column in schema view to fit UI better and change
 css to truncate field name.  changed min col width to 25.

---
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 .../collectionSchema/CollectionSchemaView.scss     |  2 ++
 .../collectionSchema/CollectionSchemaView.tsx      | 29 ++++++++--------------
 .../collectionSchema/SchemaColumnHeader.tsx        | 15 ++---------
 4 files changed, 16 insertions(+), 32 deletions(-)

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

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index c80bafe26..3a8edb1a5 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1358,7 +1358,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             case OpenWhere.inParentFromScreen:
                 const docContext = DocCast((doc instanceof Doc ? doc : doc?.[0])?.context);
                 return (
-                    (this.props.addDocument?.(
+                    (this.addDocument?.(
                         (doc instanceof Doc ? [doc] : doc).map(doc => {
                             const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y));
                             doc.x = pt[0];
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 287e2b01b..c96773298 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -115,6 +115,8 @@
     .schema-column-title {
         flex-grow: 2;
         margin: 5px;
+        overflow: hidden;
+        min-width: 20%;
     }
 
     .schema-header-menu {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index b97a2393d..d92ccc344 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -38,7 +38,7 @@ export enum ColumnType {
     Image,
 }
 
-const defaultColumnKeys: string[] = ['title', 'type', 'author', 'creationDate', 'links'];
+const defaultColumnKeys: string[] = ['title', 'type', 'author', 'creationDate', 'text'];
 
 @observer
 export class CollectionSchemaView extends CollectionSubView() {
@@ -49,7 +49,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _makeNewColumn: boolean = false;
 
     public static _rowHeight: number = 40;
-    public static _minColWidth: number = 150;
+    public static _minColWidth: number = 25;
     public static _rowMenuWidth: number = 100;
     public static _previewDividerWidth: number = 4;
 
@@ -207,16 +207,13 @@ export class CollectionSchemaView extends CollectionSubView() {
             this.addNewKey(key, defaultVal);
         }
 
-        let currWidths = [...this.storedColumnWidths];
-        const newColWidth = this.tableWidth / (currWidths.length + 1);
-        currWidths = currWidths.map(w => {
-            const proportion = w / (this.tableWidth - CollectionSchemaView._rowMenuWidth);
-            return proportion * (this.tableWidth - CollectionSchemaView._rowMenuWidth - newColWidth);
-        });
+        const newColWidth = this.tableWidth / (this.storedColumnWidths.length + 1);
+        const currWidths = this.storedColumnWidths.slice();
         currWidths.splice(0, 0, newColWidth);
-        this.layoutDoc.columnWidths = new List<number>(currWidths);
+        const newDesiredTableWidth = currWidths.reduce((w, cw) => w + cw, 0);
+        this.layoutDoc.columnWidths = new List<number>(currWidths.map(w => (w / newDesiredTableWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth)));
 
-        let currKeys = [...this.columnKeys];
+        let currKeys = this.columnKeys.slice();
         currKeys.splice(0, 0, key);
         this.layoutDoc.columnKeys = new List<string>(currKeys);
     };
@@ -230,16 +227,12 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     removeColumn = (index: number) => {
         if (this.columnKeys.length === 1) return;
-        let currWidths = [...this.storedColumnWidths];
-        const removedColWidth = currWidths[index];
-        currWidths = currWidths.map(w => {
-            const proportion = w / (this.tableWidth - CollectionSchemaView._rowMenuWidth - removedColWidth);
-            return proportion * (this.tableWidth - CollectionSchemaView._rowMenuWidth);
-        });
+        const currWidths = this.storedColumnWidths.slice();
         currWidths.splice(index, 1);
-        this.layoutDoc.columnWidths = new List<number>(currWidths);
+        const newDesiredTableWidth = currWidths.reduce((w, cw) => w + cw, 0);
+        this.layoutDoc.columnWidths = new List<number>(currWidths.map(w => (w / newDesiredTableWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth)));
 
-        let currKeys = [...this.columnKeys];
+        let currKeys = this.columnKeys.slice();
         currKeys.splice(index, 1);
         this.layoutDoc.columnKeys = new List<string>(currKeys);
     };
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index e648356f4..fffe0f4b4 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -1,21 +1,10 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable } from 'mobx';
+import { action, computed } from 'mobx';
 import { observer } from 'mobx-react';
 import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
-import './CollectionSchemaView.scss';
-import { ColumnType } from './CollectionSchemaView';
-import { IconButton } from 'browndash-components';
 import { Colors } from '../../global/globalEnums';
-import { ContextMenu } from '../../ContextMenu';
-import { Doc, DocListCast } from '../../../../fields/Doc';
-import { Id } from '../../../../fields/FieldSymbols';
-import { RichTextField } from '../../../../fields/RichTextField';
-import { StrCast } from '../../../../fields/Types';
-import { ImageField } from '../../../../fields/URLField';
-import { DocUtils, Docs } from '../../../documents/Documents';
-import { ContextMenuProps } from '../../ContextMenuItem';
-import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
+import './CollectionSchemaView.scss';
 
 export interface SchemaColumnHeaderProps {
     columnKeys: string[];
-- 
cgit v1.2.3-70-g09d2


From e4e1e346d2d0959336406edfda79c46b45787d25 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 23 Mar 2023 19:18:33 -0400
Subject: got rid of right resizer in schema view columns

---
 .../collections/collectionSchema/CollectionSchemaView.scss    |  7 -------
 .../collections/collectionSchema/CollectionSchemaView.tsx     | 11 ++++-------
 .../views/collections/collectionSchema/SchemaColumnHeader.tsx |  6 ++----
 3 files changed, 6 insertions(+), 18 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 55f320f14..769afbbf6 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -133,13 +133,6 @@
         }
     }
 
-    .schema-column-resizer.right {
-        margin-left: 5px;
-        align-self: flex-end;
-        background-color: red;
-        display: none;
-    }
-
     .schema-column-resizer.left {
         min-width: 5px;
         transform: translate(-3px, 0px);
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index d079bf839..28e0b07a4 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -238,25 +238,22 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     @action
-    startResize = (e: any, index: number, left: boolean) => {
+    startResize = (e: any, index: number) => {
         this._displayColumnWidths = this.storedColumnWidths;
-        setupMoveUpEvents(this, e, (e, delta) => this.resizeColumn(e, index, left), this.finishResize, emptyFunction);
+        setupMoveUpEvents(this, e, (e, delta) => this.resizeColumn(e, index), this.finishResize, emptyFunction);
     };
 
     @action
-    resizeColumn = (e: PointerEvent, index: number, left: boolean) => {
+    resizeColumn = (e: PointerEvent, index: number) => {
         if (this._displayColumnWidths) {
             let shrinking;
             let growing;
 
             let change = e.movementX;
 
-            if (left && index !== 0) {
+            if (index !== 0) {
                 growing = change < 0 ? index : index - 1;
                 shrinking = change < 0 ? index - 1 : index;
-            } else if (!left && index !== this.columnKeys.length - 1) {
-                growing = change > 0 ? index : index + 1;
-                shrinking = change > 0 ? index + 1 : index;
             }
 
             if (shrinking === undefined || growing === undefined) return true;
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index fffe0f4b4..cbdaeb933 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -14,7 +14,7 @@ export interface SchemaColumnHeaderProps {
     sortDesc: boolean;
     setSort: (field: string, desc: boolean) => void;
     removeColumn: (index: number) => void;
-    resizeColumn: (e: any, index: number, left: boolean) => void;
+    resizeColumn: (e: any, index: number) => void;
     dragColumn: (e: any, index: number) => boolean;
     openContextMenu: (x: number, y: number, index: number) => void;
     setColRef: (index: number, ref: HTMLDivElement) => void;
@@ -51,7 +51,7 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
                 ref={(col: HTMLDivElement | null) => {
                     col && this.props.setColRef(this.props.columnIndex, col);
                 }}>
-                <div className="schema-column-resizer left" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex, true)}></div>
+                <div className="schema-column-resizer left" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex)}></div>
                 <div className="schema-column-title">{this.fieldKey}</div>
 
                 <div className="schema-header-menu">
@@ -62,8 +62,6 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
                         <FontAwesomeIcon icon="caret-right" style={this.props.sortField == this.fieldKey ? { transform: `rotate(${this.props.sortDesc ? '270deg' : '90deg'})` } : {}} />
                     </div>
                 </div>
-
-                <div className="schema-column-resizer right" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex, false)}></div>
             </div>
         );
     }
-- 
cgit v1.2.3-70-g09d2


From c5c2c309cd88bbeb2f1b668cb040cffaac9c8470 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 4 Apr 2023 20:12:16 -0400
Subject: fixed using freeformview in sidebar of pdfs. fixed issues with
 dragging items out of schema and with selecting the schema view by clicking
 on headers.  Fixed a lot of errors caused by using OmitKeys which masks type
 checking.  fixed some pointerevent problems with treeview and freeformview

---
 src/client/documents/Documents.ts                  |  22 ++--
 src/client/views/DocumentDecorations.tsx           |  40 +++---
 src/client/views/EditableView.tsx                  |   4 +-
 src/client/views/InkStrokeProperties.ts            |   1 -
 src/client/views/InkingStroke.tsx                  |  13 +-
 src/client/views/MainView.tsx                      |   1 +
 src/client/views/PropertiesView.tsx                |  73 ++---------
 src/client/views/SidebarAnnos.tsx                  |  15 +--
 src/client/views/StyleProvider.tsx                 |   2 +-
 src/client/views/TemplateMenu.tsx                  |   2 +-
 .../views/collections/CollectionCarousel3DView.tsx |   7 +-
 .../views/collections/CollectionCarouselView.tsx   |   8 +-
 .../collections/CollectionStackedTimeline.tsx      |  54 +++-----
 .../views/collections/CollectionTreeView.tsx       |  24 ++--
 src/client/views/collections/CollectionView.tsx    |   2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 139 +++++++++++---------
 .../collections/collectionFreeForm/MarqueeView.tsx |   2 +
 .../collectionGrid/CollectionGridView.tsx          |   9 +-
 .../collectionSchema/CollectionSchemaView.tsx      |  99 +++------------
 .../collectionSchema/SchemaColumnHeader.tsx        |  10 +-
 src/client/views/nodes/AudioBox.tsx                |   6 +-
 src/client/views/nodes/ComparisonBox.tsx           |   6 +-
 src/client/views/nodes/DocumentView.tsx            |  26 +---
 src/client/views/nodes/FieldView.tsx               |   2 +-
 src/client/views/nodes/ImageBox.tsx                |  12 +-
 src/client/views/nodes/MapBox/MapBox.tsx           |   6 +-
 src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx |   5 +-
 src/client/views/nodes/PDFBox.tsx                  | 141 ++++++++++++++++-----
 src/client/views/nodes/ScreenshotBox.tsx           |  18 ++-
 src/client/views/nodes/VideoBox.tsx                |  12 +-
 src/client/views/nodes/WebBox.tsx                  |  14 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  27 ++--
 src/client/views/pdf/PDFViewer.tsx                 |  15 ++-
 src/fields/Doc.ts                                  |   9 +-
 34 files changed, 389 insertions(+), 437 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 9b8b9c877..9cb480c4a 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1420,41 +1420,39 @@ export namespace DocUtils {
 
     export function DocumentFromField(target: Doc, fieldKey: string, proto?: Doc, options?: DocumentOptions): Doc | undefined {
         let created: Doc | undefined;
-        let layout: ((fieldKey: string) => string) | undefined;
         const field = target[fieldKey];
-        const resolved = options || {};
+        const resolved = options ?? {};
         if (field instanceof ImageField) {
             created = Docs.Create.ImageDocument(field.url.href, resolved);
-            layout = ImageBox.LayoutString;
+            created.layout = ImageBox.LayoutString(fieldKey);
         } else if (field instanceof Doc) {
             created = field;
         } else if (field instanceof VideoField) {
             created = Docs.Create.VideoDocument(field.url.href, resolved);
-            layout = VideoBox.LayoutString;
+            created.layout = VideoBox.LayoutString(fieldKey);
         } else if (field instanceof PdfField) {
             created = Docs.Create.PdfDocument(field.url.href, resolved);
-            layout = PDFBox.LayoutString;
+            created.layout = PDFBox.LayoutString(fieldKey);
         } else if (field instanceof AudioField) {
             created = Docs.Create.AudioDocument(field.url.href, resolved);
-            layout = AudioBox.LayoutString;
+            created.layout = AudioBox.LayoutString(fieldKey);
         } else if (field instanceof RecordingField) {
             created = Docs.Create.RecordingDocument(field.url.href, resolved);
-            layout = RecordingBox.LayoutString;
+            created.layout = RecordingBox.LayoutString(fieldKey);
         } else if (field instanceof InkField) {
             created = Docs.Create.InkDocument(ActiveInkColor(), Doc.ActiveTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), field.inkData, ActiveIsInkMask(), resolved);
-            layout = InkingStroke.LayoutString;
+            created.layout = InkingStroke.LayoutString(fieldKey);
         } else if (field instanceof List && field[0] instanceof Doc) {
             created = Docs.Create.StackingDocument(DocListCast(field), resolved);
-            layout = CollectionView.LayoutString;
+            created.layout = CollectionView.LayoutString(fieldKey);
         } else if (field instanceof MapField) {
             created = Docs.Create.MapDocument(DocListCast(field), resolved);
-            layout = MapBox.LayoutString;
+            created.layout = MapBox.LayoutString(fieldKey);
         } else {
             created = Docs.Create.TextDocument('', { ...{ _width: 200, _height: 25, _autoHeight: true }, ...resolved });
-            layout = FormattedTextBox.LayoutString;
+            created.layout = FormattedTextBox.LayoutString(fieldKey);
         }
         if (created) {
-            created.layout = layout?.(fieldKey);
             created.title = fieldKey;
             proto && created.proto && (created.proto = Doc.GetProto(proto));
         }
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 985e6f88f..9bc583ce5 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -31,6 +31,7 @@ import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView';
 import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
 import { ImageBox } from './nodes/ImageBox';
 import React = require('react');
+import { RichTextField } from '../../fields/RichTextField';
 
 @observer
 export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> {
@@ -127,19 +128,23 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                         }
                         //@ts-ignore
                         const titleField = +this._accumulatedTitle == this._accumulatedTitle ? +this._accumulatedTitle : this._accumulatedTitle;
-                        Doc.SetInPlace(d.rootDoc, titleFieldKey, titleField, true);
 
-                        if (d.rootDoc.syncLayoutFieldWithTitle) {
-                            const title = titleField.toString();
+                        if (titleField.toString().startsWith('<this>')) {
+                            const title = titleField.toString().replace(/<this>\.?/, '');
                             const curKey = Doc.LayoutFieldKey(d.rootDoc);
-                            if (curKey !== title && d.dataDoc[title] === undefined) {
-                                d.rootDoc.layout = FormattedTextBox.LayoutString(title);
-                                setTimeout(() => {
-                                    const val = d.dataDoc[curKey];
-                                    d.dataDoc[curKey] = undefined;
-                                    d.dataDoc[title] = val;
-                                });
+                            if (curKey !== title) {
+                                if (title) {
+                                    if (d.dataDoc[title] === undefined || d.dataDoc[title] instanceof RichTextField || typeof d.dataDoc[title] === 'string') {
+                                        d.rootDoc.layoutKey = `layout_${title}`;
+                                        d.rootDoc[`layout_${title}`] = FormattedTextBox.LayoutString(title);
+                                        d.rootDoc[`${title}-nativeWidth`] = d.rootDoc[`${title}-nativeHeight`] = 0;
+                                    }
+                                } else {
+                                    d.rootDoc.layoutKey = undefined;
+                                }
                             }
+                        } else {
+                            Doc.SetInPlace(d.rootDoc, titleFieldKey, titleField, true);
                         }
                     }),
                 'title blur'
@@ -453,17 +458,6 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
 
     @action
     onPointerDown = (e: React.PointerEvent): void => {
-        const views = SelectionManager.Views().map(dv => dv.rootDoc);
-        this._inkDragDocs = views
-            .filter(doc => doc.type === DocumentType.INK)
-            .map(doc => {
-                if (InkStrokeProperties.Instance._lock) {
-                    Doc.SetNativeHeight(doc, NumCast(doc._height));
-                    Doc.SetNativeWidth(doc, NumCast(doc._width));
-                }
-                return { doc, x: NumCast(doc.x), y: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) };
-            });
-
         setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction);
         this.Interacting = true; // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them
         this._resizeHdlId = e.currentTarget.className;
@@ -487,10 +481,6 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         if (!first) return false;
         let thisPt = { x: e.clientX - this._offX, y: e.clientY - this._offY };
         var fixedAspect = Doc.NativeAspect(first.layoutDoc);
-        InkStrokeProperties.Instance._lock &&
-            SelectionManager.Views()
-                .filter(dv => dv.rootDoc.type === DocumentType.INK)
-                .forEach(dv => (fixedAspect = Doc.NativeAspect(dv.rootDoc)));
 
         const resizeHdl = this._resizeHdlId.split(' ')[0];
         if (fixedAspect && (resizeHdl === 'documentDecorations-bottomRightResizer' || resizeHdl === 'documentDecorations-topLeftResizer')) {
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index bb190e93b..164b6c57a 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -129,7 +129,7 @@ export class EditableView extends React.Component<EditableProps> {
                 this._editing = true;
                 this.props.isEditingCallback?.(true);
             }
-            e.stopPropagation();
+            // e.stopPropagation();
         }
     };
 
@@ -215,7 +215,7 @@ export class EditableView extends React.Component<EditableProps> {
                 className={`editableView-container-editing${this.props.oneLine ? '-oneLine' : ''}`}
                 ref={this._ref}
                 style={{ display: this.props.display, textOverflow: this.props.overflow, minHeight: '10px', whiteSpace: 'nowrap', height: this.props.height || 'auto', maxHeight: this.props.maxHeight }}
-                onPointerDown={e => e.stopPropagation()}
+                //onPointerDown={this.stopPropagation}
                 onClick={this.onClick}
                 placeholder={this.props.placeholder}>
                 <span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize }}>{this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()}</span>
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index 1d8d52425..e6df0801c 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -19,7 +19,6 @@ export class InkStrokeProperties {
         return this._Instance || new InkStrokeProperties();
     }
 
-    @observable _lock = false;
     @observable _controlButton = false;
     @observable _currentPoint = -1;
 
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index e3642fdaf..2fd6cc4d6 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -25,10 +25,11 @@ import { action, IReactionDisposer, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc, HeightSym, WidthSym } from '../../fields/Doc';
 import { InkData, InkField } from '../../fields/InkField';
-import { BoolCast, Cast, DocCast, NumCast, RTFCast, StrCast } from '../../fields/Types';
+import { BoolCast, Cast, NumCast, RTFCast, StrCast } from '../../fields/Types';
 import { TraceMobx } from '../../fields/util';
-import { DashColor, OmitKeys, returnFalse, setupMoveUpEvents } from '../../Utils';
+import { DashColor, returnFalse, setupMoveUpEvents } from '../../Utils';
 import { CognitiveServices } from '../cognitive_services/CognitiveServices';
+import { Docs } from '../documents/Documents';
 import { InteractionUtils } from '../util/InteractionUtils';
 import { SnappingManager } from '../util/SnappingManager';
 import { Transform } from '../util/Transform';
@@ -41,13 +42,12 @@ import { InkControlPtHandles, InkEndPtHandles } from './InkControlPtHandles';
 import './InkStroke.scss';
 import { InkStrokeProperties } from './InkStrokeProperties';
 import { InkTangentHandles } from './InkTangentHandles';
-import { DocComponentView, DocFocusOptions, DocumentView } from './nodes/DocumentView';
+import { DocComponentView } from './nodes/DocumentView';
 import { FieldView, FieldViewProps } from './nodes/FieldView';
 import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
+import { PinProps, PresBox } from './nodes/trails';
 import { StyleProp } from './StyleProvider';
 import Color = require('color');
-import { Docs } from '../documents/Documents';
-import { PinProps, PresBox } from './nodes/trails';
 
 @observer
 export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -464,7 +464,8 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
                             //top: (this.props.PanelHeight() - (lineHeightGuess * fsize + 20) * (this.props.NativeDimScaling?.() || 1)) / 2,
                         }}>
                         <FormattedTextBox
-                            {...OmitKeys(this.props, ['children']).omit}
+                            {...this.props}
+                            setHeight={undefined}
                             setContentView={this.setSubContentView} // this makes the inkingStroke the "dominant" component - ie, it will show the inking UI when selected (not text)
                             yPadding={10}
                             xPadding={10}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index f5adc17d0..befb0200d 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -259,6 +259,7 @@ export class MainView extends React.Component {
                 fa.faConciergeBell,
                 fa.faWindowRestore,
                 fa.faFolder,
+                fa.faFolderOpen,
                 fa.faMapPin,
                 fa.faMapMarker,
                 fa.faFingerprint,
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index f3a5a5393..fbc7d7696 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -102,7 +102,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
     @observable inOptions: boolean = false;
     @observable _controlButton: boolean = false;
-    @observable _lock: boolean = false;
 
     componentDidMount() {
         this.selectedDocListenerDisposer?.();
@@ -586,16 +585,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         <FontAwesomeIcon icon="bezier-curve" color="white" size="lg" />
                     </div>
                 </Tooltip>
-                <Tooltip title={<div className="dash-tooltip">{InkStrokeProperties.Instance._lock ? 'Unlock ratio' : 'Lock ratio'}</div>}>
-                    <div className="inking-button-lock" onPointerDown={action(() => (InkStrokeProperties.Instance._lock = !InkStrokeProperties.Instance._lock))}>
-                        <FontAwesomeIcon icon={InkStrokeProperties.Instance._lock ? 'lock' : 'unlock'} color="white" size="lg" />
-                    </div>
-                </Tooltip>
-                <Tooltip title={<div className="dash-tooltip">{'Rotate 90˚'}</div>}>
-                    <div className="inking-button-rotate" onPointerDown={action(() => this.rotate(Math.PI / 2))}>
-                        <FontAwesomeIcon icon="undo" color="white" size="lg" />
-                    </div>
-                </Tooltip>
             </div>
         );
     }
@@ -644,9 +633,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     @action
     upDownButtons = (dirs: string, field: string) => {
         switch (field) {
-            case 'rot':
-                this.rotate(dirs === 'up' ? 0.1 : -0.1);
-                break;
             case 'Xps':
                 this.selectedDoc && (this.selectedDoc.x = NumCast(this.selectedDoc?.x) + (dirs === 'up' ? 10 : -10));
                 break;
@@ -662,7 +648,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 const oldX = NumCast(this.selectedDoc?.x);
                 const oldY = NumCast(this.selectedDoc?.y);
                 this.selectedDoc && (this.selectedDoc._width = oldWidth + (dirs === 'up' ? 10 : -10));
-                InkStrokeProperties.Instance._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) / oldWidth) * NumCast(this.selectedDoc?._height));
                 const doc = this.selectedDoc;
                 if (doc?.type === DocumentType.INK && doc.x && doc.y && doc._height && doc._width) {
                     const ink = Cast(doc.data, InkField)?.inkData;
@@ -684,7 +669,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 const oX = NumCast(this.selectedDoc?.x);
                 const oY = NumCast(this.selectedDoc?.y);
                 this.selectedDoc && (this.selectedDoc._height = oHeight + (dirs === 'up' ? 10 : -10));
-                InkStrokeProperties.Instance._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) / oHeight) * NumCast(this.selectedDoc?._width));
                 const docu = this.selectedDoc;
                 if (docu?.type === DocumentType.INK && docu.x && docu.y && docu._height && docu._width) {
                     const ink = Cast(docu.data, InkField)?.inkData;
@@ -704,11 +688,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     };
 
     getField(key: string) {
-        //if (this.selectedDoc) {
         return Field.toString(this.selectedDoc?.[key] as Field);
-        // } else {
-        //     return undefined as Opt<string>;
-        // }
     }
 
     @computed get shapeXps() {
@@ -717,9 +697,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     @computed get shapeYps() {
         return this.getField('y');
     }
-    @computed get shapeRot() {
-        return this.getField('rotation');
-    }
     @computed get shapeHgt() {
         return this.getField('_height');
     }
@@ -732,18 +709,11 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     set shapeYps(value) {
         this.selectedDoc && (this.selectedDoc.y = Number(value));
     }
-    set shapeRot(value) {
-        this.selectedDoc && (this.selectedDoc.rotation = Number(value));
-    }
     set shapeWid(value) {
-        const oldWidth = NumCast(this.selectedDoc?._width);
         this.selectedDoc && (this.selectedDoc._width = Number(value));
-        InkStrokeProperties.Instance._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) * NumCast(this.selectedDoc?._height)) / oldWidth);
     }
     set shapeHgt(value) {
-        const oldHeight = NumCast(this.selectedDoc?._height);
         this.selectedDoc && (this.selectedDoc._height = Number(value));
-        InkStrokeProperties.Instance._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) * NumCast(this.selectedDoc?._width)) / oldHeight);
     }
 
     @computed get hgtInput() {
@@ -790,30 +760,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             'Y:'
         );
     }
-    @computed get rotInput() {
-        return this.inputBoxDuo(
-            'rot',
-            this.shapeRot,
-            (val: string) => {
-                if (!isNaN(Number(val))) {
-                    this.rotate(Number(val) - Number(this.shapeRot));
-                    this.shapeRot = val;
-                }
-                return true;
-            },
-            '∠:',
-            'rot',
-            this.shapeRot,
-            (val: string) => {
-                if (!isNaN(Number(val))) {
-                    this.rotate(Number(val) - Number(this.shapeRot));
-                    this.shapeRot = val;
-                }
-                return true;
-            },
-            ''
-        );
-    }
 
     @observable private _fillBtn = false;
     @observable private _lineBtn = false;
@@ -1080,10 +1026,9 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     @computed get transformEditor() {
         return (
             <div className="transform-editor">
-                {this.controlPointsButton}
+                {this.isInk ? this.controlPointsButton : null}
                 {this.hgtInput}
                 {this.XpsInput}
-                {this.rotInput}
             </div>
         );
     }
@@ -1194,17 +1139,15 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     </div>
                 )}
 
-                {this.isInk ? (
-                    <div className="propertiesView-transform">
-                        <div className="propertiesView-transform-title" onPointerDown={action(() => (this.openTransform = !this.openTransform))} style={{ backgroundColor: this.openTransform ? 'black' : '' }}>
-                            Transform
-                            <div className="propertiesView-transform-title-icon">
-                                <FontAwesomeIcon icon={this.openTransform ? 'caret-down' : 'caret-right'} size="lg" color="white" />
-                            </div>
+                <div className="propertiesView-transform">
+                    <div className="propertiesView-transform-title" onPointerDown={action(() => (this.openTransform = !this.openTransform))} style={{ backgroundColor: this.openTransform ? 'black' : '' }}>
+                        Transform
+                        <div className="propertiesView-transform-title-icon">
+                            <FontAwesomeIcon icon={this.openTransform ? 'caret-down' : 'caret-right'} size="lg" color="white" />
                         </div>
-                        {this.openTransform ? <div className="propertiesView-transform-content">{this.transformEditor}</div> : null}
                     </div>
-                ) : null}
+                    {this.openTransform ? <div className="propertiesView-transform-content">{this.transformEditor}</div> : null}
+                </div>
             </>
         );
     }
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 02dd15960..48c0150e6 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -5,7 +5,7 @@ import { Id } from '../../fields/FieldSymbols';
 import { List } from '../../fields/List';
 import { RichTextField } from '../../fields/RichTextField';
 import { DocCast, NumCast, StrCast } from '../../fields/Types';
-import { emptyFunction, OmitKeys, returnAll, returnOne, returnTrue, returnZero } from '../../Utils';
+import { emptyFunction, returnAll, returnFalse, returnOne, returnTrue, returnZero } from '../../Utils';
 import { Docs, DocUtils } from '../documents/Documents';
 import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
 import { LinkManager } from '../util/LinkManager';
@@ -26,6 +26,7 @@ interface ExtraProps {
     // usePanelWidth: boolean;
     showSidebar: boolean;
     nativeWidth: number;
+    usePanelWidth?: boolean;
     whenChildContentsActiveChanged: (isActive: boolean) => void;
     ScreenToLocalTransform: () => Transform;
     sidebarAddDocument: (doc: Doc | Doc[], suffix: string) => boolean;
@@ -158,13 +159,10 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
             .ScreenToLocalTransform()
             .translate(Doc.NativeWidth(this.props.dataDoc), 0)
             .scale(this.props.NativeDimScaling?.() || 1);
-    // panelWidth = () => !this.props.layoutDoc._showSidebar ? 0 :
-    //     this.props.usePanelWidth ? this.props.PanelWidth() :
-    //         (NumCast(this.props.layoutDoc.nativeWidth) - Doc.NativeWidth(this.props.dataDoc)) * this.props.PanelWidth() / NumCast(this.props.layoutDoc.nativeWidth);
     panelWidth = () =>
         !this.props.showSidebar
             ? 0
-            : this.props.layoutDoc.type === DocumentType.RTF || this.props.layoutDoc.type === DocumentType.MAP
+            : this.props.usePanelWidth // [DocumentType.RTF, DocumentType.MAP].includes(this.props.layoutDoc.type as any)
             ? this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1)
             : ((NumCast(this.props.nativeWidth) - Doc.NativeWidth(this.props.dataDoc)) * this.props.PanelWidth()) / NumCast(this.props.nativeWidth);
     panelHeight = () => this.props.PanelHeight() - this.filtersHeight();
@@ -224,20 +222,21 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
                 </div>
                 <div style={{ width: '100%', height: `calc(100% - 38px)`, position: 'relative' }}>
                     <CollectionStackingView
-                        {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
-                        ref={this._stackRef}
+                        {...this.props}
+                        setContentView={emptyFunction}
                         NativeWidth={returnZero}
                         NativeHeight={returnZero}
+                        ref={this._stackRef}
                         PanelHeight={this.panelHeight}
                         PanelWidth={this.panelWidth}
                         docFilters={this.docFilters}
-                        scaleField={this.sidebarKey + '-scale'}
                         sortFunc={this.sortByLinkAnchorY}
                         setHeight={this.setHeightCallback}
                         isAnnotationOverlay={false}
                         select={emptyFunction}
                         NativeDimScaling={returnOne}
                         //childShowTitle={this.showTitle}
+                        isAnyChildContentActive={returnFalse}
                         childDocumentsActive={this.props.isContentActive}
                         whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
                         childHideDecorationTitle={returnTrue}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 50cf8eba7..f7b9420a7 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -170,7 +170,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             const docColor: Opt<string> = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color));
             if (docColor) return docColor;
             const docView = props?.DocumentView?.();
-            const backColor = backgroundCol() || docView?.props.styleProvider?.(docView.props.treeViewDoc, docView.props, 'backgroundColor');
+            const backColor = backgroundCol() || docView?.props.styleProvider?.(docView.props.treeViewDoc, docView.props, StyleProp.BackgroundColor);
             if (!backColor) return undefined;
             return lightOrDark(backColor);
         case StyleProp.Hidden:
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 681ff66e0..45db240a9 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -79,7 +79,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
     };
     componentDidMount() {
         !this._addedKeys && (this._addedKeys = new ObservableSet());
-        Array.from(Object.keys(Doc.GetProto(this.props.docViews[0].props.Document)))
+        [...Array.from(Object.keys(Doc.GetProto(this.props.docViews[0].props.Document))), ...Array.from(Object.keys(this.props.docViews[0].props.Document))]
             .filter(key => key.startsWith('layout_'))
             .map(key => runInAction(() => this._addedKeys.add(key.replace('layout_', ''))));
     }
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index 57ff1b292..a266c9207 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -5,7 +5,7 @@ import * as React from 'react';
 import { Doc } from '../../../fields/Doc';
 import { Id } from '../../../fields/FieldSymbols';
 import { NumCast, ScriptCast, StrCast } from '../../../fields/Types';
-import { OmitKeys, returnFalse, Utils } from '../../../Utils';
+import { returnFalse, returnZero, Utils } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { DocumentView } from '../nodes/DocumentView';
 import { StyleProp } from '../StyleProvider';
@@ -43,7 +43,10 @@ export class CollectionCarousel3DView extends CollectionSubView() {
         const displayDoc = (childPair: { layout: Doc; data: Doc }) => {
             return (
                 <DocumentView
-                    {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'childLayoutTemplate', 'childLayoutString']).omit}
+                    {...this.props}
+                    NativeWidth={returnZero}
+                    NativeHeight={returnZero}
+                    suppressSetHeight={true}
                     onDoubleClick={this.onChildDoubleClick}
                     renderDepth={this.props.renderDepth + 1}
                     LayoutTemplate={this.props.childLayoutTemplate}
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 32f6207ed..c0220f804 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -4,7 +4,7 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, Opt } from '../../../fields/Doc';
 import { NumCast, ScriptCast, StrCast } from '../../../fields/Types';
-import { OmitKeys, returnFalse } from '../../../Utils';
+import { emptyFunction, returnFalse, returnZero } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { DocumentView, DocumentViewProps } from '../nodes/DocumentView';
 import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
@@ -47,7 +47,7 @@ export class CollectionCarouselView extends CollectionSubView() {
     @computed get content() {
         const index = NumCast(this.layoutDoc._itemIndex);
         const curDoc = this.childLayoutPairs?.[index];
-        const captionProps = { ...OmitKeys(this.props, ['setHeight']).omit, fieldKey: 'caption' };
+        const captionProps = { ...this.props, fieldKey: 'caption', setHeight: undefined };
         const marginX = NumCast(this.layoutDoc['caption-xMargin']);
         const marginY = NumCast(this.layoutDoc['caption-yMargin']);
         const showCaptions = StrCast(this.layoutDoc._showCaption);
@@ -55,7 +55,9 @@ export class CollectionCarouselView extends CollectionSubView() {
             <>
                 <div className="collectionCarouselView-image" key="image">
                     <DocumentView
-                        {...OmitKeys(this.props, ['setHeight', 'NativeWidth', 'NativeHeight', 'childLayoutTemplate', 'childLayoutString']).omit}
+                        {...this.props}
+                        NativeWidth={returnZero}
+                        NativeHeight={returnZero}
                         onDoubleClick={this.onContentDoubleClick}
                         onClick={this.onContentClick}
                         hideCaptions={showCaptions ? true : false}
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 4941bc722..642d29d2a 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -9,7 +9,7 @@ import { listSpec } from '../../../fields/Schema';
 import { ComputedField, ScriptField } from '../../../fields/ScriptField';
 import { Cast, NumCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
-import { emptyFunction, formatTime, OmitKeys, returnFalse, returnNone, returnOne, returnTrue, setupMoveUpEvents, smoothScrollHorizontal, StopEvent } from '../../../Utils';
+import { emptyFunction, formatTime, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnTrue, returnZero, setupMoveUpEvents, smoothScrollHorizontal, StopEvent } from '../../../Utils';
 import { Docs } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { DocumentManager } from '../../util/DocumentManager';
@@ -23,7 +23,6 @@ import { Transform } from '../../util/Transform';
 import { undoBatch, UndoManager } from '../../util/UndoManager';
 import { AudioWaveform } from '../AudioWaveform';
 import { CollectionSubView } from '../collections/CollectionSubView';
-import { Colors } from '../global/globalEnums';
 import { LightboxView } from '../LightboxView';
 import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps } from '../nodes/DocumentView';
 import { LabelBox } from '../nodes/LabelBox';
@@ -512,37 +511,6 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
 
     currentTimecode = () => this.currentTime;
 
-    @computed get renderDictation() {
-        const dictation = Cast(this.dataDoc[this.props.dictationKey], Doc, null);
-        return !dictation ? null : (
-            <div
-                style={{
-                    position: 'absolute',
-                    height: '100%',
-                    top: this.timelineContentHeight,
-                    background: Colors.LIGHT_BLUE,
-                }}>
-                <DocumentView
-                    {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
-                    Document={dictation}
-                    PanelHeight={this.dictationHeight}
-                    isAnnotationOverlay={true}
-                    isDocumentActive={returnFalse}
-                    select={emptyFunction}
-                    NativeDimScaling={returnOne}
-                    xMargin={25}
-                    yMargin={10}
-                    ScreenToLocalTransform={this.dictationScreenToLocalTransform}
-                    whenChildContentsActiveChanged={emptyFunction}
-                    removeDocument={returnFalse}
-                    moveDocument={returnFalse}
-                    addDocument={returnFalse}
-                    CollectionView={undefined}
-                    renderDepth={this.props.renderDepth + 1}></DocumentView>
-            </div>
-        );
-    }
-
     // renders selection region on timeline
     @computed get selectionContainer() {
         const markerEnd = CollectionStackedTimeline.SelectingRegion === this ? this.currentTime : this._markerEnd;
@@ -638,7 +606,6 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
                                 PanelWidth={this.timelineContentWidth}
                             />
                         )}
-                        {/* {this.renderDictation} */}
 
                         <div
                             className="collectionStackedTimeline-hover"
@@ -817,16 +784,22 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
     // renders anchor LabelBox
     renderInner = computedFn(function (this: StackedTimelineAnchor, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), screenXf: () => Transform, width: () => number, height: () => number) {
         const anchor = observable({ view: undefined as any });
-        const focusFunc = (doc: Doc, options: DocFocusOptions) => this.props.playLink(mark);
+        const focusFunc = (doc: Doc, options: DocFocusOptions): number | undefined => {
+            this.props.playLink(mark);
+            return undefined;
+        };
         return {
             anchor,
             view: (
                 <DocumentView
                     key="view"
-                    {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight']).omit}
+                    {...this.props}
+                    NativeWidth={returnZero}
+                    NativeHeight={returnZero}
                     ref={action((r: DocumentView | null) => (anchor.view = r))}
                     Document={mark}
                     DataDoc={undefined}
+                    docViewPath={returnEmptyDoclist}
                     pointerEvents={this.noEvents ? returnNone : undefined}
                     styleProvider={this.props.styleProvider}
                     renderDepth={this.props.renderDepth + 1}
@@ -837,7 +810,16 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
                     PanelHeight={height}
                     fitWidth={returnTrue}
                     ScreenToLocalTransform={screenXf}
+                    addDocTab={returnFalse}
+                    pinToPres={emptyFunction}
+                    whenChildContentsActiveChanged={emptyFunction}
                     focus={focusFunc}
+                    isContentActive={returnFalse}
+                    ContainingCollectionView={undefined}
+                    ContainingCollectionDoc={undefined}
+                    searchFilterDocs={returnEmptyDoclist}
+                    docFilters={returnEmptyFilter}
+                    docRangeFilters={returnEmptyFilter}
                     rootSelected={returnFalse}
                     onClick={script}
                     onDoubleClick={this.props.layoutDoc.autoPlayAnchors ? undefined : doublescript}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 553967b95..4a11e8f0b 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -7,7 +7,7 @@ import { listSpec } from '../../../fields/Schema';
 import { ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, OmitKeys, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue } from '../../../Utils';
+import { emptyFunction, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero } from '../../../Utils';
 import { DocUtils } from '../../documents/Documents';
 import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager, dropActionType } from '../../util/DragManager';
@@ -384,12 +384,12 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
         this.props.CollectionView?.moveDocument(doc, targetCollection, addDocument, `${this.props.fieldKey}-annotations`) || false;
 
     @observable _headerHeight = 0;
-    contentFunc = () => {
+    @computed get content() {
         const background = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor);
         const pointerEvents = () => (!this.props.isContentActive() && !SnappingManager.GetIsDragging() ? 'none' : undefined);
         const titleBar = this.props.treeViewHideTitle || this.doc.treeViewHideTitle ? null : this.titleBar;
-        return [
-            <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
+        return (
+            <div style={{ display: 'flex', flexDirection: 'column', height: '100%', pointerEvents: 'all' }}>
                 {!this.buttonMenu && !this.noviceExplainer ? null : (
                     <div className="documentButtonMenu" ref={action((r: HTMLDivElement | null) => r && (this._headerHeight = Number(getComputedStyle(r).height.replace(/px/, ''))))}>
                         {this.buttonMenu}
@@ -428,9 +428,9 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                         </div>
                     </div>
                 </div>
-            </div>,
-        ];
-    };
+            </div>
+        );
+    }
     render() {
         TraceMobx();
 
@@ -439,7 +439,11 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
             <div style={{ transform: `scale(${scale})`, transformOrigin: 'top left', width: `${100 / scale}%`, height: `${100 / scale}%` }}>
                 {!(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeViewHasOverlay ? (
                     <CollectionFreeFormView
-                        {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
+                        {...this.props}
+                        setContentView={emptyFunction}
+                        NativeWidth={returnZero}
+                        NativeHeight={returnZero}
+                        pointerEvents={SnappingManager.GetIsDragging() ? returnAll : returnNone}
                         isAnnotationOverlay={true}
                         isAnnotationOverlayScrollable={true}
                         childDocumentsActive={this.props.isDocumentActive}
@@ -451,10 +455,10 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                         moveDocument={this.moveAnnotationDocument}
                         bringToFront={emptyFunction}
                         renderDepth={this.props.renderDepth + 1}>
-                        {this.contentFunc}
+                        {this.content}
                     </CollectionFreeFormView>
                 ) : (
-                    this.contentFunc()
+                    this.content
                 )}
             </div>
         );
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 51624689e..bc25ad43a 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -45,7 +45,7 @@ interface CollectionViewProps_ extends FieldViewProps {
 
     // property overrides for child documents
     childDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox)
-    childDocumentsActive?: () => boolean; // whether child documents can be dragged if collection can be dragged (eg., in a when a Pile document is in startburst mode)
+    childDocumentsActive?: () => boolean | undefined; // whether child documents can be dragged if collection can be dragged (eg., in a when a Pile document is in startburst mode)
     childFitWidth?: (child: Doc) => boolean;
     childShowTitle?: () => string;
     childOpacity?: () => number;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index aed3683d4..d39668a5d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,6 +1,6 @@
 import { Bezier } from 'bezier-js';
 import { Colors } from 'browndash-components';
-import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
+import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import { DateField } from '../../../../fields/DateField';
@@ -53,10 +53,14 @@ import { MarqueeView } from './MarqueeView';
 import React = require('react');
 
 export type collectionFreeformViewProps = {
+    noPointerWheel?: () => boolean; // turn off pointerwheel interactions (see PDFViewer)
+    NativeWidth?: () => number;
+    NativeHeight?: () => number;
+    originTopLeft?: boolean;
     annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox)
     viewDefDivClick?: ScriptField;
     childPointerEvents?: string;
-    scaleField?: string;
+    viewField?: string;
     noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale)
     engineProps?: any;
     getScrollHeight?: () => number | undefined;
@@ -97,8 +101,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     private get isAnnotationOverlay() {
         return this.props.isAnnotationOverlay;
     }
-    private get scaleFieldKey() {
-        return this.props.scaleField || '_viewScale';
+    public get scaleFieldKey() {
+        return this.props.viewField ? this.props.viewField + '-viewScale' : '_viewScale';
+    }
+    private get panXFieldKey() {
+        return this.props.viewField ? this.props.viewField + '-panX' : '_panX';
+    }
+    private get panYFieldKey() {
+        return this.props.viewField ? this.props.viewField + '-panY' : '_panY';
     }
     private get borderWidth() {
         return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH;
@@ -149,21 +159,21 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                   );
     }
     @computed get nativeWidth() {
-        return this.fitContentsToBox ? 0 : Doc.NativeWidth(this.Document, Cast(this.Document.resolvedDataDoc, Doc, null));
+        return this.props.NativeWidth?.() || (this.fitContentsToBox ? 0 : Doc.NativeWidth(this.Document, Cast(this.Document.resolvedDataDoc, Doc, null)));
     }
     @computed get nativeHeight() {
-        return this.fitContentsToBox ? 0 : Doc.NativeHeight(this.Document, Cast(this.Document.resolvedDataDoc, Doc, null));
+        return this.props.NativeHeight?.() || (this.fitContentsToBox ? 0 : Doc.NativeHeight(this.Document, Cast(this.Document.resolvedDataDoc, Doc, null)));
     }
     @computed get cachedCenteringShiftX(): number {
         const scaling = this.fitContentsToBox || !this.nativeDimScaling ? 1 : this.nativeDimScaling;
-        return this.props.isAnnotationOverlay ? 0 : this.props.PanelWidth() / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
+        return this.props.isAnnotationOverlay || this.props.originTopLeft ? 0 : this.props.PanelWidth() / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
     }
     @computed get cachedCenteringShiftY(): number {
         const dv = this.props.DocumentView?.();
         const scaling = this.fitContentsToBox || !this.nativeDimScaling ? 1 : this.nativeDimScaling;
         // if freeform has a native aspect, then the panel height needs to be adjusted to match it
         const aspect = dv?.nativeWidth && dv?.nativeHeight && !dv.layoutDoc.fitWidth ? dv.nativeHeight / dv.nativeWidth : this.props.PanelHeight() / this.props.PanelWidth();
-        return this.props.isAnnotationOverlay ? 0 : (aspect * this.props.PanelWidth()) / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
+        return this.props.isAnnotationOverlay || this.props.originTopLeft ? 0 : (aspect * this.props.PanelWidth()) / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
     }
     @computed get cachedGetLocalTransform(): Transform {
         return Transform.Identity()
@@ -236,13 +246,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     reverseNativeScaling = () => (this.fitContentsToBox ? true : false);
     // panx, pany, zoomscale all attempt to get values first from the layout controller, then from the layout/dataDoc (or template layout doc), and finally from the resolved template data document.
     // this search order, for example, allows icons of cropped images to find the panx/pany/zoom on the cropped image's data doc instead of the usual layout doc because the zoom/panX/panY define the cropped image
-    panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document._panX, NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panX, 1));
-    panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document._panY, NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panY, 1));
+    panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document[this.panXFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panX, 1));
+    panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document[this.panYFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panY, 1));
     zoomScaling = () => this.freeformData()?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.[this.scaleFieldKey], 1));
     contentTransform = () =>
-        !this.cachedCenteringShiftX && !this.cachedCenteringShiftY && this.zoomScaling() === 1
-            ? ''
-            : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`;
+        this.props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`;
     getTransform = () => this.cachedGetTransform.copy();
     getLocalTransform = () => this.cachedGetLocalTransform.copy();
     getContainerTransform = () => this.cachedGetContainerTransform.copy();
@@ -293,7 +301,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     }
 
     groupFocus = (anchor: Doc, options: DocFocusOptions) => {
-        options.docTransform = new Transform(-NumCast(this.rootDoc.panX) + NumCast(anchor.x), -NumCast(this.rootDoc.panY) + NumCast(anchor.y), 1);
+        options.docTransform = new Transform(-NumCast(this.rootDoc[this.panXFieldKey]) + NumCast(anchor.x), -NumCast(this.rootDoc[this.panYFieldKey]) + NumCast(anchor.y), 1);
         const res = this.props.focus(this.rootDoc, options);
         options.docTransform = undefined;
         return res;
@@ -301,7 +309,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     focus = (anchor: Doc, options: DocFocusOptions) => {
         const xfToCollection = options?.docTransform ?? Transform.Identity();
-        const savedState = { panX: NumCast(this.Document._panX), panY: NumCast(this.Document._panY), scale: options?.willZoomCentered ? this.Document[this.scaleFieldKey] : undefined };
+        const savedState = { panX: NumCast(this.Document[this.panXFieldKey]), panY: NumCast(this.Document[this.panYFieldKey]), scale: options?.willZoomCentered ? this.Document[this.scaleFieldKey] : undefined };
         const cantTransform = this.fitContentsToBox || ((this.rootDoc._isGroup || this.layoutDoc._lockedTransform) && !LightboxView.LightboxDoc);
         const { panX, panY, scale } = cantTransform || (!options.willPan && !options.willZoomCentered) ? savedState : this.calculatePanIntoView(anchor, xfToCollection, options?.willZoomCentered ? options?.zoomScale || 0.75 : undefined);
 
@@ -772,7 +780,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         PresBox.Instance?.pauseAutoPres();
         const dx = e.deltaX;
         const dy = e.deltaY;
-        this.setPan(NumCast(this.Document._panX) - dx, NumCast(this.Document._panY) - dy, 0, true);
+        this.setPan(NumCast(this.Document[this.panXFieldKey]) - dx, NumCast(this.Document[this.panYFieldKey]) - dy, 0, true);
     };
 
     @action
@@ -780,7 +788,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         PresBox.Instance?.pauseAutoPres();
         this.props.DocumentView?.().clearViewTransition();
         const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
-        this.setPan(NumCast(this.Document._panX) - dx, NumCast(this.Document._panY) - dy, 0, true);
+        this.setPan(NumCast(this.Document[this.panXFieldKey]) - dx, NumCast(this.Document[this.panYFieldKey]) - dy, 0, true);
         this._lastX = e.clientX;
         this._lastY = e.clientY;
     };
@@ -979,13 +987,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         if (localTransform.Scale >= 0.05 || localTransform.Scale > this.zoomScaling()) {
             const safeScale = Math.min(Math.max(0.05, localTransform.Scale), 20);
             this.props.Document[this.scaleFieldKey] = Math.abs(safeScale);
-            this.setPan(-localTransform.TranslateX / safeScale, NumCast(this.props.Document.scrollTop) * safeScale || -localTransform.TranslateY / safeScale);
+            this.setPan(-localTransform.TranslateX / safeScale, (this.props.originTopLeft ? undefined : NumCast(this.props.Document.scrollTop) * safeScale) || -localTransform.TranslateY / safeScale);
         }
     };
 
     @action
     onPointerWheel = (e: React.WheelEvent): void => {
-        if (this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom
+        if (this.props.noPointerWheel?.() || this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom
         PresBox.Instance?.pauseAutoPres();
         if (this.layoutDoc._Transform || DocListCast(Doc.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return;
         e.stopPropagation();
@@ -995,7 +1003,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 // if ctrl is selected then zoom
                 if (e.ctrlKey) {
                     if (this.props.isContentActive(true)) {
-                        !this.props.isAnnotationOverlayScrollable && this.zoom(e.clientX, e.clientY, e.deltaY); // if (!this.props.isAnnotationOverlay) // bcz: do we want to zoom in on images/videos/etc?
+                        this.zoom(e.clientX, e.clientY, e.deltaY); // if (!this.props.isAnnotationOverlay) // bcz: do we want to zoom in on images/videos/etc?
                     }
                 } // otherwise pan
                 else if (this.props.isContentActive(true)) {
@@ -1039,16 +1047,19 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                         yrange: { min: Math.min(yrange.min, pos.y), max: Math.max(yrange.max, pos.y + (size.height || 0)) },
                     }),
                     {
-                        xrange: { min: Number.MAX_VALUE, max: -Number.MAX_VALUE },
-                        yrange: { min: Number.MAX_VALUE, max: -Number.MAX_VALUE },
+                        xrange: { min: this.props.originTopLeft ? 0 : Number.MAX_VALUE, max: -Number.MAX_VALUE },
+                        yrange: { min: this.props.originTopLeft ? 0 : Number.MAX_VALUE, max: -Number.MAX_VALUE },
                     }
                 );
 
-                const panelDim = [this.props.PanelWidth() / this.zoomScaling(), this.props.PanelHeight() / this.zoomScaling()];
-                if (ranges.xrange.min >= panX + panelDim[0] / 2) panX = ranges.xrange.max + panelDim[0] / 2; // snaps pan position of range of content goes out of bounds
-                else if (ranges.xrange.max <= panX - panelDim[0] / 2) panX = ranges.xrange.min - panelDim[0] / 2;
-                if (ranges.yrange.min >= panY + panelDim[1] / 2) panY = ranges.yrange.max + panelDim[1] / 2;
-                else if (ranges.yrange.max <= panY - panelDim[1] / 2) panY = ranges.yrange.min - panelDim[1] / 2;
+                const panelWidMax = (this.props.PanelWidth() / this.zoomScaling()) * (this.props.originTopLeft ? 2 / this.nativeDimScaling : 1);
+                const panelWidMin = (this.props.PanelWidth() / this.zoomScaling()) * (this.props.originTopLeft ? 0 : 1);
+                const panelHgtMax = (this.props.PanelHeight() / this.zoomScaling()) * (this.props.originTopLeft ? 2 / this.nativeDimScaling : 1);
+                const panelHgtMin = (this.props.PanelHeight() / this.zoomScaling()) * (this.props.originTopLeft ? 0 : 1);
+                if (ranges.xrange.min >= panX + panelWidMax / 2) panX = ranges.xrange.max + (this.props.originTopLeft ? 0 : panelWidMax / 2);
+                else if (ranges.xrange.max <= panX - panelWidMin / 2) panX = ranges.xrange.min - (this.props.originTopLeft ? panelWidMax / 2 : panelWidMin / 2);
+                if (ranges.yrange.min >= panY + panelHgtMax / 2) panY = ranges.yrange.max + (this.props.originTopLeft ? 0 : panelHgtMax / 2);
+                else if (ranges.yrange.max <= panY - panelHgtMin / 2) panY = ranges.yrange.min - (this.props.originTopLeft ? panelHgtMax / 2 : panelHgtMin / 2);
             }
         }
         if (!this.layoutDoc._lockedTransform || LightboxView.LightboxDoc || DocListCast(Doc.MyOverlayDocs?.data).includes(this.Document)) {
@@ -1078,8 +1089,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 }, 10);
                 newPanY = minPanY;
             }
-            !this.Document._verticalScroll && (this.Document._panX = this.isAnnotationOverlay ? newPanX : panX);
-            !this.Document._horizontalScroll && (this.Document._panY = this.isAnnotationOverlay ? newPanY : panY);
+            !this.Document._verticalScroll && (this.Document[this.panXFieldKey] = this.isAnnotationOverlay ? newPanX : panX);
+            !this.Document._horizontalScroll && (this.Document[this.panYFieldKey] = this.isAnnotationOverlay ? newPanY : panY);
         }
     }
 
@@ -1087,8 +1098,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     nudge = (x: number, y: number, nudgeTime: number = 500) => {
         if (this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform || this.props.ContainingCollectionDoc._panX !== undefined) {
             this.setPan(
-                NumCast(this.layoutDoc._panX) + ((this.props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale
-                NumCast(this.layoutDoc._panY) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(),
+                NumCast(this.layoutDoc[this.panXFieldKey]) + ((this.props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale
+                NumCast(this.layoutDoc[this.panYFieldKey]) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(),
                 nudgeTime,
                 true
             );
@@ -1106,12 +1117,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         } else {
             const docs = this.childLayoutPairs.map(pair => pair.layout).slice();
             docs.sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex));
-            let zlast = docs.length ? Math.max(docs.length, NumCast(docs[docs.length - 1].zIndex)) : 1;
-            if (zlast - docs.length > 100) {
-                for (let i = 0; i < docs.length; i++) doc.zIndex = i + 1;
-                zlast = docs.length + 1;
+            let zlast = docs.length ? Math.max(docs.length, NumCast(docs.lastElement().zIndex)) : 1;
+            if (docs.lastElement() !== doc) {
+                if (zlast - docs.length > 100) {
+                    for (let i = 0; i < docs.length; i++) doc.zIndex = i + 1;
+                    zlast = docs.length + 1;
+                }
+                doc.zIndex = zlast + 1;
             }
-            doc.zIndex = zlast + 1;
         }
     };
 
@@ -1134,8 +1147,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const newScreenXY = this.getTransform().inverse().transformPoint(docpt[0], docpt[1]);
         const scrDelta = { x: screenXY[0] - newScreenXY[0], y: screenXY[1] - newScreenXY[1] };
         const newpan = this.getTransform().transformDirection(scrDelta.x, scrDelta.y);
-        this.layoutDoc._panX = NumCast(this.layoutDoc._panX) - newpan[0];
-        this.layoutDoc._panY = NumCast(this.layoutDoc._panY) - newpan[1];
+        this.layoutDoc[this.panXFieldKey] = NumCast(this.layoutDoc[this.panXFieldKey]) - newpan[0];
+        this.layoutDoc[this.panYFieldKey] = NumCast(this.layoutDoc[this.panYFieldKey]) - newpan[1];
     }
 
     calculatePanIntoView = (doc: Doc, xf: Transform, scale?: number) => {
@@ -1158,8 +1171,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const panelHeight = this.props.isAnnotationOverlay ? this.nativeHeight : this.props.PanelHeight();
         const pw = panelWidth / NumCast(this.layoutDoc._viewScale, 1);
         const ph = panelHeight / NumCast(this.layoutDoc._viewScale, 1);
-        const cx = NumCast(this.layoutDoc._panX) + (this.props.isAnnotationOverlay ? pw / 2 : 0);
-        const cy = NumCast(this.layoutDoc._panY) + (this.props.isAnnotationOverlay ? ph / 2 : 0);
+        const cx = NumCast(this.layoutDoc[this.panXFieldKey]) + (this.props.isAnnotationOverlay ? pw / 2 : 0);
+        const cy = NumCast(this.layoutDoc[this.panYFieldKey]) + (this.props.isAnnotationOverlay ? ph / 2 : 0);
         const screen = { left: cx - pw / 2, right: cx + pw / 2, top: cy - ph / 2, bot: cy + ph / 2 };
         const maxYShift = Math.max(0, screen.bot - screen.top - (bounds.bot - bounds.top));
         const phborder = bounds.top < screen.top || bounds.bot > screen.bot ? Math.min(ph / 10, maxYShift / 2) : 0;
@@ -1171,8 +1184,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             };
         }
         return {
-            panX: (this.props.isAnnotationOverlay ? NumCast(this.layoutDoc._panX) : cx) + Math.min(0, bounds.left - pw / 10 - screen.left) + Math.max(0, bounds.right + pw / 10 - screen.right),
-            panY: (this.props.isAnnotationOverlay ? NumCast(this.layoutDoc._panY) : cy) + Math.min(0, bounds.top - phborder - screen.top) + Math.max(0, bounds.bot + phborder - screen.bot),
+            panX: (this.props.isAnnotationOverlay ? NumCast(this.layoutDoc[this.panXFieldKey]) : cx) + Math.min(0, bounds.left - pw / 10 - screen.left) + Math.max(0, bounds.right + pw / 10 - screen.right),
+            panY: (this.props.isAnnotationOverlay ? NumCast(this.layoutDoc[this.panYFieldKey]) : cy) + Math.min(0, bounds.top - phborder - screen.top) + Math.max(0, bounds.bot + phborder - screen.bot),
         };
     };
 
@@ -1459,7 +1472,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
         if (this.props.isAnnotationOverlay && this.props.Document[this.scaleFieldKey]) {
             // don't zoom out farther than 1-1 if it's a bounded item (image, video, pdf), otherwise don't allow zooming in closer than 1-1 if it's a text sidebar
-            if (this.props.scaleField) this.props.Document[this.scaleFieldKey] = Math.min(1, this.zoomScaling());
+            if (this.props.viewField) this.props.Document[this.scaleFieldKey] = Math.min(1, this.zoomScaling());
             else this.props.Document[this.scaleFieldKey] = Math.max(1, this.zoomScaling()); // NumCast(this.props.Document[this.scaleFieldKey]));
         }
 
@@ -1501,7 +1514,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                     cbounds => {
                         if (cbounds) {
                             const c = [NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym]() / 2, NumCast(this.layoutDoc.y) + this.layoutDoc[HeightSym]() / 2];
-                            const p = [NumCast(this.layoutDoc._panX), NumCast(this.layoutDoc._panY)];
+                            const p = [NumCast(this.layoutDoc[this.panXFieldKey]), NumCast(this.layoutDoc[this.panYFieldKey])];
                             const pbounds = {
                                 x: cbounds.x - p[0] + c[0],
                                 y: cbounds.y - p[1] + c[1],
@@ -1511,8 +1524,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                             if (Number.isFinite(pbounds.r - pbounds.x) && Number.isFinite(pbounds.b - pbounds.y)) {
                                 this.layoutDoc._width = pbounds.r - pbounds.x;
                                 this.layoutDoc._height = pbounds.b - pbounds.y;
-                                this.layoutDoc._panX = (cbounds.r + cbounds.x) / 2;
-                                this.layoutDoc._panY = (cbounds.b + cbounds.y) / 2;
+                                this.layoutDoc[this.panXFieldKey] = (cbounds.r + cbounds.x) / 2;
+                                this.layoutDoc[this.panYFieldKey] = (cbounds.b + cbounds.y) / 2;
                                 this.layoutDoc.x = pbounds.x;
                                 this.layoutDoc.y = pbounds.y;
                             }
@@ -1634,8 +1647,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             const deltaX = dragX - bounds.left < 25 ? -(25 + (bounds.left - dragX)) : bounds.right - dragX < 25 ? 25 - (bounds.right - dragX) : 0;
             const deltaY = dragY - bounds.top < 25 ? -(25 + (bounds.top - dragY)) : bounds.bottom - dragY < 25 ? 25 - (bounds.bottom - dragY) : 0;
             if (deltaX !== 0 || deltaY !== 0) {
-                this.Document._panY = NumCast(this.Document._panY) + deltaY / 2;
-                this.Document._panX = NumCast(this.Document._panX) + deltaX / 2;
+                this.Document[this.panYFieldKey] = NumCast(this.Document[this.panYFieldKey]) + deltaY / 2;
+                this.Document[this.panXFieldKey] = NumCast(this.Document[this.panXFieldKey]) + deltaX / 2;
             }
         }
         e.stopPropagation();
@@ -1659,8 +1672,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const height = Math.max(...docs.map(doc => NumCast(doc._height))) + 20;
         const dim = Math.ceil(Math.sqrt(docs.length));
         docs.forEach((doc, i) => {
-            doc.x = NumCast(this.Document._panX) + (i % dim) * width - (width * dim) / 2;
-            doc.y = NumCast(this.Document._panY) + Math.floor(i / dim) * height - (height * dim) / 2;
+            doc.x = NumCast(this.Document[this.panXFieldKey]) + (i % dim) * width - (width * dim) / 2;
+            doc.y = NumCast(this.Document[this.panYFieldKey]) + Math.floor(i / dim) * height - (height * dim) / 2;
         });
     };
 
@@ -1675,7 +1688,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         appearanceItems.push({
             description: 'Reset View',
             event: () => {
-                this.props.Document._panX = this.props.Document._panY = 0;
+                this.props.Document[this.panXFieldKey] = this.props.Document[this.panYFieldKey] = 0;
                 this.props.Document[this.scaleFieldKey] = 1;
             },
             icon: 'compress-arrows-alt',
@@ -1795,11 +1808,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         this.childDocs.some(doc => !this._renderCutoffData.get(doc[Id])) && setTimeout(this.incrementalRender, 1);
     });
 
-    children = () => {
+    get children() {
         this.incrementalRender();
-        const children = typeof this.props.children === 'function' ? ((this.props.children as any)() as JSX.Element[]) : [];
+        const children = typeof this.props.children === 'function' ? ((this.props.children as any)() as JSX.Element[]) : this.props.children ? [this.props.children] : [];
         return [...children, ...this.views, <CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" />];
-    };
+    }
 
     @computed get placeholder() {
         return (
@@ -1843,6 +1856,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                                 PanelHeight={this.props.PanelHeight}
                                 panX={this.panX}
                                 panY={this.panY}
+                                nativeDimScaling={this.nativeDim}
                                 zoomScaling={this.zoomScaling}
                                 layoutDoc={this.layoutDoc}
                                 isAnnotationOverlay={this.isAnnotationOverlay}
@@ -1877,6 +1891,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const wscale = nw ? this.props.PanelWidth() / nw : 1;
         return wscale < hscale || this.layoutDoc.fitWidth ? wscale : hscale;
     }
+    nativeDim = () => this.nativeDimScaling;
 
     private groupDropDisposer?: DragManager.DragDropDisposer;
     protected createGroupEventsTarget = (ele: HTMLDivElement) => {
@@ -1912,7 +1927,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 ref={r => {
                     this.createDashEventsTarget(r);
                     // prevent wheel events from passivly propagating up through containers
-                    r?.addEventListener('wheel', (e: WheelEvent) => this.props.isSelected() && e.preventDefault(), { passive: false });
+                    !this.props.isAnnotationOverlay && r?.addEventListener('wheel', (e: WheelEvent) => this.props.isSelected() && e.preventDefault(), { passive: false });
                 }}
                 onWheel={this.onPointerWheel}
                 onClick={this.onClick}
@@ -1985,7 +2000,8 @@ interface CollectionFreeFormViewPannableContentsProps {
     transform: () => string;
     zoomScaling: () => number;
     viewDefDivClick?: ScriptField;
-    children: () => JSX.Element[];
+    children?: React.ReactNode | undefined;
+    //children: () => JSX.Element[];
     transition?: string;
     presPaths: () => JSX.Element | null;
     presPinView?: boolean;
@@ -2079,7 +2095,7 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
                     width: this.props.isAnnotationOverlay ? undefined : 0, // if not an overlay, then this will be the size of the collection, but panning and zooming will move it outside the visible border of the collection and make it selectable.  This problem shows up after zooming/panning on a background collection -- you can drag the collection by clicking on apparently empty space outside the collection
                     //willChange: "transform"
                 }}>
-                {this.props.children()}
+                {this.props.children}
                 {!this.props.brushView.width ? null : (
                     <div
                         className="collectionFreeFormView-brushView"
@@ -2107,6 +2123,7 @@ interface CollectionFreeFormViewBackgroundGridProps {
     PanelWidth: () => number;
     PanelHeight: () => number;
     isAnnotationOverlay?: boolean;
+    nativeDimScaling: () => number;
     zoomScaling: () => number;
     layoutDoc: Doc;
     cachedCenteringShiftX: number;
@@ -2124,10 +2141,10 @@ class CollectionFreeFormBackgroundGrid extends React.Component<CollectionFreeFor
         const shiftX = (this.props.isAnnotationOverlay ? 0 : (-this.props.panX() % gridSpace) - gridSpace) * this.props.zoomScaling();
         const shiftY = (this.props.isAnnotationOverlay ? 0 : (-this.props.panY() % gridSpace) - gridSpace) * this.props.zoomScaling();
         const renderGridSpace = gridSpace * this.props.zoomScaling();
-        const w = this.props.PanelWidth() + 2 * renderGridSpace;
-        const h = this.props.PanelHeight() + 2 * renderGridSpace;
+        const w = this.props.PanelWidth() / this.props.nativeDimScaling() + 2 * renderGridSpace;
+        const h = this.props.PanelHeight() / this.props.nativeDimScaling() + 2 * renderGridSpace;
         const strokeStyle = Doc.ActiveDashboard?.colorScheme === ColorScheme.Dark ? 'rgba(255,255,255,0.5)' : 'rgba(0, 0,0,0.5)';
-        return (
+        return !this.props.nativeDimScaling() ? null : (
             <canvas
                 className="collectionFreeFormView-grid"
                 width={w}
@@ -2174,7 +2191,7 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY
         const selfFfview = !dv.rootDoc._isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined;
         let parFfview = dv.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
         while (parFfview?.rootDoc._isGroup) parFfview = parFfview.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
-        const ffview = selfFfview && selfFfview.rootDoc[selfFfview.props.scaleField || '_viewScale'] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it.  Otherwise, zoom out on the parent ffview
+        const ffview = selfFfview && selfFfview.rootDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it.  Otherwise, zoom out on the parent ffview
         ffview?.zoomSmoothlyAboutPt(ffview.getTransform().transformPoint(clientX, clientY), 0.5, browseTransitionTime);
         Doc.linkFollowHighlight(dv?.props.Document, false);
     } else {
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index f16371592..043fe0bcf 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -237,6 +237,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
 
     @action
     onPointerDown = (e: React.PointerEvent): void => {
+        // if (this.props.pointerEvents?.() === 'none') return;
         this._downX = this._lastX = e.clientX;
         this._downY = this._lastY = e.clientY;
         if (!(e.nativeEvent as any).marqueeHit) {
@@ -345,6 +346,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
 
     @action
     onClick = (e: React.MouseEvent): void => {
+        if (this.props.pointerEvents?.() === 'none') return;
         if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
             if (Doc.ActiveTool === InkTool.None) {
                 if (!(e.nativeEvent as any).marqueeHit) {
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index 9468c5f06..e8ae88ae5 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -4,7 +4,7 @@ import * as React from 'react';
 import { Doc, Opt } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, OmitKeys, returnFalse, setupMoveUpEvents } from '../../../../Utils';
+import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents } from '../../../../Utils';
 import { Docs } from '../../../documents/Documents';
 import { DragManager } from '../../../util/DragManager';
 import { SnappingManager } from '../../../util/SnappingManager';
@@ -186,7 +186,10 @@ export class CollectionGridView extends CollectionSubView() {
     getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) {
         return (
             <DocumentView
-                {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight']).omit}
+                {...this.props}
+                NativeWidth={returnZero}
+                NativeHeight={returnZero}
+                setContentView={emptyFunction}
                 Document={layout}
                 DataDoc={layout.resolvedDataDoc as Doc}
                 isContentActive={this.isChildContentActive}
@@ -196,7 +199,7 @@ export class CollectionGridView extends CollectionSubView() {
                 whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
                 onClick={this.onChildClickHandler}
                 renderDepth={this.props.renderDepth + 1}
-                dontCenter={this.props.Document.centerY ? '' : 'y'}
+                dontCenter={this.props.Document.centerY ? undefined : 'y'}
             />
         );
     }
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index d47c9762c..fd9bcf681 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,23 +1,20 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, ObservableMap, trace, untracked } from 'mobx';
+import { action, computed, observable, ObservableMap, untracked } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, DocListCast, Field, StrListCast } from '../../../../fields/Doc';
+import { computedFn } from 'mobx-utils';
+import { Doc, Field, StrListCast } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
-import { RichTextField } from '../../../../fields/RichTextField';
 import { listSpec } from '../../../../fields/Schema';
 import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
-import { ImageField } from '../../../../fields/URLField';
 import { emptyFunction, returnDefault, returnEmptyDoclist, returnEmptyString, returnFalse, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils';
 import { Docs, DocUtils } from '../../../documents/Documents';
 import { DocumentManager } from '../../../util/DocumentManager';
 import { DragManager } from '../../../util/DragManager';
 import { SelectionManager } from '../../../util/SelectionManager';
-import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
 import { ContextMenu } from '../../ContextMenu';
-import { ContextMenuProps } from '../../ContextMenuItem';
 import { EditableView } from '../../EditableView';
 import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView';
 import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
@@ -215,9 +212,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     @action
-    addNewKey = (key: string, defaultVal: any) => {
-        this.childDocs.forEach(doc => (doc[key] = defaultVal));
-    };
+    addNewKey = (key: string, defaultVal: any) => this.childDocs.forEach(doc => (doc[key] = defaultVal));
 
     @undoBatch
     @action
@@ -303,9 +298,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     @action
-    addRowRef = (doc: Doc, ref: HTMLDivElement) => {
-        this._rowEles.set(doc, ref);
-    };
+    addRowRef = (doc: Doc, ref: HTMLDivElement) => this._rowEles.set(doc, ref);
 
     @action
     setColRef = (index: number, ref: HTMLDivElement) => {
@@ -405,68 +398,12 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     menuCallback = (x: number, y: number) => {
         ContextMenu.Instance.clearItems();
-        const layoutItems: ContextMenuProps[] = [];
-        const docItems: ContextMenuProps[] = [];
-        const dataDoc = this.props.DataDoc || this.props.Document;
-
-        DocUtils.addDocumentCreatorMenuItems(
-            doc => {
-                FormattedTextBox.SelectOnLoad = StrCast(doc[Id]);
-                return this.addRow(doc);
-            },
-            this.addRow,
-            x,
-            y,
-            true
-        );
 
-        Array.from(Object.keys(Doc.GetProto(dataDoc)))
-            .filter(fieldKey => dataDoc[fieldKey] instanceof RichTextField || dataDoc[fieldKey] instanceof ImageField || typeof dataDoc[fieldKey] === 'string')
-            .map(fieldKey =>
-                docItems.push({
-                    description: ':' + fieldKey,
-                    event: () => {
-                        const created = DocUtils.DocumentFromField(dataDoc, fieldKey, Doc.GetProto(this.props.Document));
-                        if (created) {
-                            if (this.props.Document.isTemplateDoc) {
-                                Doc.MakeMetadataFieldTemplate(created, this.props.Document);
-                            }
-                            return this.addRow(created);
-                        }
-                    },
-                    icon: 'compress-arrows-alt',
-                })
-            );
-        Array.from(Object.keys(Doc.GetProto(dataDoc)))
-            .filter(fieldKey => DocListCast(dataDoc[fieldKey]).length)
-            .map(fieldKey =>
-                docItems.push({
-                    description: ':' + fieldKey,
-                    event: () => {
-                        const created = Docs.Create.CarouselDocument([], { _width: 400, _height: 200, title: fieldKey });
-                        if (created) {
-                            const container = this.props.Document.resolvedDataDoc ? Doc.GetProto(this.props.Document) : this.props.Document;
-                            if (container.isTemplateDoc) {
-                                Doc.MakeMetadataFieldTemplate(created, container);
-                                return Doc.AddDocToList(container, Doc.LayoutFieldKey(container), created);
-                            }
-                            return this.addRow(created) || false;
-                        }
-                    },
-                    icon: 'compress-arrows-alt',
-                })
-            );
-        !Doc.noviceMode && ContextMenu.Instance.addItem({ description: 'Doc Fields ...', subitems: docItems, icon: 'eye' });
-        !Doc.noviceMode && ContextMenu.Instance.addItem({ description: 'Containers ...', subitems: layoutItems, icon: 'eye' });
+        DocUtils.addDocumentCreatorMenuItems(doc => this.addRow(doc), this.addRow, x, y, true);
+
         ContextMenu.Instance.setDefaultItem('::', (name: string): void => {
             Doc.GetProto(this.props.Document)[name] = '';
-            const created = Docs.Create.TextDocument('', { title: name, _autoHeight: true });
-            if (created) {
-                if (this.props.Document.isTemplateDoc) {
-                    Doc.MakeMetadataFieldTemplate(created, this.props.Document);
-                }
-                this.addRow(created);
-            }
+            this.addRow(Docs.Create.TextDocument('', { title: name, _autoHeight: true }));
         });
         ContextMenu.Instance.displayMenu(x, y, undefined, true);
     };
@@ -543,9 +480,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     @action
-    closeColumnMenu = () => {
-        this._columnMenuIndex = undefined;
-    };
+    closeColumnMenu = () => (this._columnMenuIndex = undefined);
 
     @action
     openFilterMenu = (index: number) => {
@@ -596,19 +531,14 @@ export class CollectionSchemaView extends CollectionSubView() {
     getFieldFilters = (field: string) => StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field);
 
     removeFieldFilters = (field: string) => {
-        this.getFieldFilters(field).forEach(filter => {
-            Doc.setDocFilter(this.Document, field, filter.split(':')[1], 'remove');
-        });
+        this.getFieldFilters(field).forEach(filter => Doc.setDocFilter(this.Document, field, filter.split(':')[1], 'remove'));
     };
 
     onFilterKeyDown = (e: React.KeyboardEvent) => {
+        //prettier-ignore
         switch (e.key) {
-            case 'Enter':
-                this.closeFilterMenu(true);
-                break;
-            case 'Escape':
-                this.closeFilterMenu(false);
-                break;
+            case 'Enter' : this.closeFilterMenu(true); break;
+            case 'Escape': this.closeFilterMenu(false);break;
         }
     };
 
@@ -903,6 +833,7 @@ interface CollectionSchemaViewDocsProps {
 class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsProps> {
     tableWidthFunc = () => this.props.schema.tableWidth;
     rowHeightFunc = () => CollectionSchemaView._rowHeight;
+    childScreenToLocal = computedFn((index: number) => () => this.props.schema.props.ScreenToLocalTransform().translate(0, -CollectionSchemaView._rowHeight - index * this.rowHeightFunc()));
     render() {
         return (
             <div className="schema-table-content">
@@ -932,7 +863,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 docRangeFilters={this.props.schema.childDocRangeFilters}
                                 searchFilterDocs={this.props.schema.searchFilterDocs}
                                 rootSelected={this.props.schema.rootSelected}
-                                ScreenToLocalTransform={Transform.Identity}
+                                ScreenToLocalTransform={this.childScreenToLocal(index)}
                                 bringToFront={emptyFunction}
                                 isDocumentActive={this.props.schema.props.childDocumentsActive?.() ? this.props.schema.props.isDocumentActive : this.props.schema.isContentActive}
                                 isContentActive={emptyFunction}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index cbdaeb933..d88d67c94 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -39,18 +39,12 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
 
     @action
     onPointerDown = (e: React.PointerEvent) => {
-        setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction);
+        setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction, false);
     };
 
     render() {
         return (
-            <div
-                className="schema-column-header"
-                style={{ width: this.props.columnWidths[this.props.columnIndex] }}
-                onPointerDown={this.onPointerDown}
-                ref={(col: HTMLDivElement | null) => {
-                    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 => 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>
 
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 384975b45..a6acf882c 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -7,7 +7,7 @@ import { Doc, DocListCast } from '../../../fields/Doc';
 import { ComputedField } from '../../../fields/ScriptField';
 import { Cast, DateCast, NumCast } from '../../../fields/Types';
 import { AudioField, nullAudio } from '../../../fields/URLField';
-import { emptyFunction, formatTime, OmitKeys, returnFalse, setupMoveUpEvents } from '../../../Utils';
+import { emptyFunction, formatTime, returnFalse, setupMoveUpEvents } from '../../../Utils';
 import { DocUtils } from '../../documents/Documents';
 import { Networking } from '../../Network';
 import { DragManager } from '../../util/DragManager';
@@ -19,7 +19,6 @@ import { ContextMenuProps } from '../ContextMenuItem';
 import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
 import './AudioBox.scss';
 import { FieldView, FieldViewProps } from './FieldView';
-import { SelectionManager } from '../../util/SelectionManager';
 import { PinProps, PresBox } from './trails';
 
 /**
@@ -655,7 +654,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         return (
             <CollectionStackedTimeline
                 ref={action((r: any) => (this._stackedTimeline = r))}
-                {...OmitKeys(this.props, ['CollectionFreeFormDocumentView']).omit}
+                {...this.props}
+                CollectionFreeFormDocumentView={undefined}
                 fieldKey={this.annotationKey}
                 dictationKey={this.fieldKey + '-dictation'}
                 mediaPath={this.path}
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index ecffe6c4f..ace388c57 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -3,7 +3,7 @@ import { action, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc, Opt } from '../../../fields/Doc';
 import { Cast, NumCast, StrCast } from '../../../fields/Types';
-import { emptyFunction, OmitKeys, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils';
+import { emptyFunction, returnFalse, returnNone, returnZero, setupMoveUpEvents } from '../../../Utils';
 import { Docs } from '../../documents/Documents';
 import { DragManager } from '../../util/DragManager';
 import { SnappingManager } from '../../util/SnappingManager';
@@ -122,7 +122,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                         ref={r => {
                             //whichDoc !== targetDoc && r?.focus(whichDoc, { instant: true });
                         }}
-                        {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight']).omit}
+                        {...this.props}
+                        NativeWidth={returnZero}
+                        NativeHeight={returnZero}
                         isContentActive={returnFalse}
                         isDocumentActive={returnFalse}
                         styleProvider={this.docStyleProvider}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 091a6b050..c7bf37a45 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -12,7 +12,7 @@ import { ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { AudioField } from '../../../fields/URLField';
 import { GetEffectiveAcl, TraceMobx } from '../../../fields/util';
-import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, OmitKeys, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils';
+import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils';
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { DocServer } from '../../DocServer';
 import { Docs, DocUtils } from '../../documents/Documents';
@@ -512,7 +512,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 this.props.isDocumentActive?.() &&
                 !this.props.onBrowseClick?.() &&
                 !this.Document.ignoreClick &&
-                !e.ctrlKey &&
                 e.button === 0 &&
                 this.pointerEvents !== 'none' &&
                 !DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)
@@ -705,22 +704,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             const appearance = cm.findByDescription('UI Controls...');
             const appearanceItems: ContextMenuProps[] = appearance && 'subitems' in appearance ? appearance.subitems : [];
             !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template   ', event: () => this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' });
-            !Doc.noviceMode &&
-                appearanceItems.push({
-                    description: 'Add a Field',
-                    event: () => {
-                        const alias = Doc.MakeAlias(this.rootDoc);
-                        alias.layout = FormattedTextBox.LayoutString('newfield');
-                        alias.title = 'newfield';
-                        alias._height = 35;
-                        alias._width = 100;
-                        alias.syncLayoutFieldWithTitle = true;
-                        alias.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc.width);
-                        alias.y = NumCast(this.rootDoc.y);
-                        this.props.addDocument?.(alias);
-                    },
-                    icon: 'eye',
-                });
             LinkManager.Links(this.Document).length &&
                 appearanceItems.splice(0, 0, { description: `${this.layoutDoc.hideLinkButton ? 'Show' : 'Hide'} Link Button`, event: action(() => (this.layoutDoc.hideLinkButton = !this.layoutDoc.hideLinkButton)), icon: 'eye' });
             !appearance && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' });
@@ -863,7 +846,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     onClickFunc: any = () => (this.disableClickScriptFunc ? undefined : this.onClickHandler);
     setHeight = (height: number) => (this.layoutDoc._height = height);
     setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view));
-    isContentActive = (outsideReaction?: boolean) => {
+    isContentActive = (outsideReaction?: boolean): boolean | undefined => {
         return this.props.isContentActive() === false
             ? false
             : Doc.ActiveTool !== InkTool.None ||
@@ -1064,7 +1047,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         }
     };
 
-    captionStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps>, property: string) => this.props?.styleProvider?.(doc, props, property + ':caption');
+    captionStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => this.props?.styleProvider?.(doc, props, property + ':caption');
     @computed get innards() {
         TraceMobx();
         const ffscale = () => this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.ScreenToLocalTransform().Scale || 1;
@@ -1079,7 +1062,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     maxHeight: `max(100%, ${20 * ffscale()}px)`,
                 }}>
                 <FormattedTextBox
-                    {...OmitKeys(this.props, ['children']).omit}
+                    {...this.props}
                     yPadding={10}
                     xPadding={10}
                     fieldKey={this.showCaption}
@@ -1090,7 +1073,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     dontScale={true}
                     renderDepth={this.props.renderDepth}
                     isContentActive={this.isContentActive}
-                    onClick={this.onClickFunc}
                 />
             </div>
         );
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index e53422ab7..8d3534a5c 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -20,7 +20,7 @@ export interface FieldViewProps extends DocumentViewSharedProps {
 
     select: (isCtrlPressed: boolean) => void;
     isContentActive: (outsideReaction?: boolean) => boolean | undefined;
-    isDocumentActive?: () => boolean;
+    isDocumentActive?: () => boolean | undefined;
     isSelected: (outsideReaction?: boolean) => boolean;
     setHeight?: (height: number) => void;
     NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal NOTE: Must also be added to DocumentViewInternalsProps
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 48e54b722..b5193cd20 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -11,7 +11,7 @@ import { ComputedField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
 import { TraceMobx } from '../../../fields/util';
-import { DashColor, emptyFunction, OmitKeys, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../Utils';
+import { DashColor, emptyFunction, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils';
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices';
 import { Docs, DocUtils } from '../../documents/Documents';
@@ -409,8 +409,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         );
     }
 
-    contentFunc = () => [this.content];
-
     private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
     private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
     @observable _marqueeing: number[] | undefined;
@@ -473,7 +471,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 }}>
                 <CollectionFreeFormView
                     ref={this._ffref}
-                    {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
+                    {...this.props}
+                    setContentView={emptyFunction}
+                    NativeWidth={returnZero}
+                    NativeHeight={returnZero}
                     renderDepth={this.props.renderDepth + 1}
                     fieldKey={this.annotationKey}
                     styleProvider={this.props.styleProvider}
@@ -487,11 +488,12 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     focus={this.focus}
                     getScrollHeight={this.getScrollHeight}
                     NativeDimScaling={returnOne}
+                    isAnyChildContentActive={returnFalse}
                     whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                     removeDocument={this.removeDocument}
                     moveDocument={this.moveDocument}
                     addDocument={this.addDocument}>
-                    {this.contentFunc}
+                    {this.content}
                 </CollectionFreeFormView>
                 {this.annotationLayer}
                 {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : (
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index ea8f47b39..36be7d257 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -8,7 +8,7 @@ import { Doc, DocListCast, Opt, WidthSym } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
 import { InkTool } from '../../../../fields/InkField';
 import { NumCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, OmitKeys, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils';
+import { emptyFunction, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils';
 import { Docs } from '../../../documents/Documents';
 import { DragManager } from '../../../util/DragManager';
 import { SnappingManager } from '../../../util/SnappingManager';
@@ -635,7 +635,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                                 .map(marker => (
                                     <MapBoxInfoWindow
                                         key={marker[Id]}
-                                        {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
+                                        {...this.props}
+                                        setContentView={emptyFunction}
                                         place={marker}
                                         markerMap={this.markerMap}
                                         PanelWidth={this.infoWidth}
@@ -674,6 +675,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         rootDoc={this.rootDoc}
                         layoutDoc={this.layoutDoc}
                         dataDoc={this.dataDoc}
+                        usePanelWidth={true}
                         showSidebar={this.SidebarShown}
                         nativeWidth={NumCast(this.layoutDoc._nativeWidth)}
                         whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
index 00bedafbe..d65ef9c4c 100644
--- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
+++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
@@ -4,7 +4,7 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
-import { emptyFunction, OmitKeys, returnAll, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents } from '../../../../Utils';
+import { emptyFunction, returnAll, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents } from '../../../../Utils';
 import { Docs } from '../../../documents/Documents';
 import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
 import { CollectionNoteTakingView } from '../../collections/CollectionNoteTakingView';
@@ -52,7 +52,8 @@ export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps & Vi
                     <div style={{ width: this.props.PanelWidth(), height: this.props.PanelHeight() }}>
                         <CollectionStackingView
                             ref={r => (this._stack = r)}
-                            {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
+                            {...this.props}
+                            setContentView={emptyFunction}
                             Document={this.props.place}
                             DataDoc={undefined}
                             fieldKey="data"
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 5f207cc0d..a254edd87 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -5,16 +5,20 @@ import * as Pdfjs from 'pdfjs-dist';
 import 'pdfjs-dist/web/pdf_viewer.css';
 import { Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
 import { Id } from '../../../fields/FieldSymbols';
-import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types';
+import { InkTool } from '../../../fields/InkField';
+import { ComputedField } from '../../../fields/ScriptField';
+import { Cast, FieldValue, ImageCast, NumCast, StrCast } from '../../../fields/Types';
 import { ImageField, PdfField } from '../../../fields/URLField';
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, setupMoveUpEvents, Utils } from '../../../Utils';
+import { emptyFunction, returnFalse, setupMoveUpEvents, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
-import { DocumentType } from '../../documents/DocumentTypes';
+import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
 import { DocumentManager } from '../../util/DocumentManager';
 import { KeyCodes } from '../../util/KeyCodes';
+import { SelectionManager } from '../../util/SelectionManager';
 import { undoBatch, UndoManager } from '../../util/UndoManager';
 import { CollectionFreeFormView } from '../collections/collectionFreeForm';
+import { CollectionStackingView } from '../collections/CollectionStackingView';
 import { ContextMenu } from '../ContextMenu';
 import { ContextMenuProps } from '../ContextMenuItem';
 import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
@@ -41,7 +45,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     private _initialScrollTarget: Opt<Doc>;
     private _pdfViewer: PDFViewer | undefined;
     private _searchRef = React.createRef<HTMLInputElement>();
-    private _selectReactionDisposer: IReactionDisposer | undefined;
+    private _disposers: { [name: string]: IReactionDisposer } = {};
     private _sidebarRef = React.createRef<SidebarAnnos>();
 
     @observable private _searching: boolean = false;
@@ -184,11 +188,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     };
 
     componentWillUnmount() {
-        this._selectReactionDisposer?.();
+        Object.values(this._disposers).forEach(disposer => disposer?.());
     }
     componentDidMount() {
         this.props.setContentView?.(this);
-        this._selectReactionDisposer = reaction(
+        this._disposers.select = reaction(
             () => this.props.isSelected(),
             () => {
                 document.removeEventListener('keydown', this.onKeyDown);
@@ -196,6 +200,16 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             },
             { fireImmediately: true }
         );
+        this._disposers.scroll = reaction(
+            () => this.rootDoc.scrollTop,
+            () => {
+                if (!(ComputedField.WithoutComputed(() => FieldValue(this.props.Document[this.SidebarKey + '-panY'])) instanceof ComputedField)) {
+                    this.props.Document[this.SidebarKey + '-panY'] = ComputedField.MakeFunction('this.scrollTop');
+                }
+                this.props.Document[this.SidebarKey + '-viewScale'] = 1;
+                this.props.Document[this.SidebarKey + '-panX'] = 0;
+            }
+        );
     }
 
     brushView = (view: { width: number; height: number; panX: number; panY: number }) => this._pdfViewer?.brushView(view);
@@ -303,7 +317,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     // adding external documents; to sidebar key
     // if (doc.Geolocation) this.addDocument(doc, this.fieldkey+"-annotation")
-    sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
+    sidebarAddDocument = (doc: Doc | Doc[], sidebarKey: string = this.SidebarKey) => {
         if (!this.layoutDoc._showSidebar) this.toggleSidebar();
         return this.addDocument(doc, sidebarKey);
     };
@@ -428,6 +442,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     };
     specificContextMenu = (e: React.MouseEvent): void => {
         const funcs: ContextMenuProps[] = [];
+        funcs.push({
+            description: 'Toggle Sidebar Type',
+            event: () => (this.rootDoc.sidebarViewType = this.rootDoc.sidebarViewType === CollectionViewType.Freeform ? CollectionViewType.Stacking : CollectionViewType.Freeform),
+            icon: 'expand-arrows-alt',
+        });
         funcs.push({ description: 'Copy path', event: () => this.pdfUrl && Utils.CopyText(Utils.prepend('') + this.pdfUrl.url.pathname), icon: 'expand-arrows-alt' });
         funcs.push({ description: 'update icon', event: () => this.pdfUrl && this.updateIcon(), icon: 'expand-arrows-alt' });
         //funcs.push({ description: "Toggle Sidebar ", event: () => this.toggleSidebar(), icon: "expand-arrows-alt" });
@@ -467,12 +486,87 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         );
     }
 
+    public get SidebarKey() {
+        return this.fieldKey + '-sidebar';
+    }
+    @computed get pdfScale() {
+        const pdfNativeWidth = NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']);
+        const nativeWidth = NumCast(this.layoutDoc.nativeWidth, pdfNativeWidth);
+        const pdfRatio = pdfNativeWidth / nativeWidth;
+        return (pdfRatio * this.props.PanelWidth()) / pdfNativeWidth;
+    }
+    @computed get sidebarNativeWidth() {
+        return this.sidebarWidth() / this.pdfScale;
+    }
+    @computed get sidebarNativeHeight() {
+        return this.props.PanelHeight() / this.pdfScale;
+    }
+    sidebarNativeWidthFunc = () => this.sidebarNativeWidth;
+    sidebarNativeHeightFunc = () => this.sidebarNativeHeight;
+    sidebarMoveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.moveDocument(doc, targetCollection, addDocument, this.SidebarKey);
+    sidebarRemDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, this.SidebarKey);
+    sidebarScreenToLocal = () => this.props.ScreenToLocalTransform().translate((this.sidebarWidth() - this.props.PanelWidth()) / this.pdfScale, 0);
+    @computed get sidebarCollection() {
+        const renderComponent = (tag: string) => {
+            const ComponentTag = tag === CollectionViewType.Freeform ? CollectionFreeFormView : CollectionStackingView;
+            return ComponentTag === CollectionStackingView ? (
+                <SidebarAnnos
+                    ref={this._sidebarRef}
+                    {...this.props}
+                    rootDoc={this.rootDoc}
+                    layoutDoc={this.layoutDoc}
+                    dataDoc={this.dataDoc}
+                    setHeight={emptyFunction}
+                    nativeWidth={this._previewNativeWidth ?? NumCast(this.layoutDoc._nativeWidth)}
+                    showSidebar={this.SidebarShown}
+                    whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
+                    sidebarAddDocument={this.sidebarAddDocument}
+                    moveDocument={this.moveDocument}
+                    removeDocument={this.removeDocument}
+                    //PanelWidth={this.sidebarWidth}
+                    //ScreenToLocalTransform={this.sidebarScreenToLocal}
+                />
+            ) : (
+                <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.props.DocumentView?.()!, false), true)}>
+                    <ComponentTag
+                        {...this.props}
+                        setContentView={emptyFunction} // override setContentView to do nothing
+                        NativeWidth={this.sidebarNativeWidthFunc}
+                        NativeHeight={this.sidebarNativeHeightFunc}
+                        PanelHeight={this.props.PanelHeight}
+                        PanelWidth={this.sidebarWidth}
+                        xPadding={0}
+                        yPadding={0}
+                        viewField={this.SidebarKey}
+                        isAnnotationOverlay={false}
+                        originTopLeft={true}
+                        isAnyChildContentActive={this.isAnyChildContentActive}
+                        select={emptyFunction}
+                        whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
+                        removeDocument={this.sidebarRemDocument}
+                        moveDocument={this.sidebarMoveDocument}
+                        addDocument={this.sidebarAddDocument}
+                        CollectionView={undefined}
+                        ScreenToLocalTransform={this.sidebarScreenToLocal}
+                        renderDepth={this.props.renderDepth + 1}
+                        noSidebar={true}
+                        fieldKey={this.SidebarKey}
+                    />
+                </div>
+            );
+        };
+        return (
+            <div className={'formattedTextBox-sidebar' + (Doc.ActiveTool !== InkTool.None ? '-inking' : '')} style={{ width: '100%', right: 0, backgroundColor: `white` }}>
+                {renderComponent(StrCast(this.layoutDoc.sidebarViewType))}
+            </div>
+        );
+    }
     isPdfContentActive = () => this.isAnyChildContentActive() || this.props.isSelected() || (this.props.renderDepth === 0 && LightboxView.IsLightboxDocView(this.props.docViewPath()));
     @computed get renderPdfView() {
         TraceMobx();
         const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
         const scale = previewScale * (this.props.NativeDimScaling?.() || 1);
-        return (
+        return !this._pdf ? null : (
             <div
                 className={'pdfBox'}
                 onContextMenu={this.specificContextMenu}
@@ -496,7 +590,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         addDocTab={this.sidebarAddDocTab}
                         layoutDoc={this.layoutDoc}
                         dataDoc={this.dataDoc}
-                        pdf={this._pdf!}
+                        pdf={this._pdf}
                         focus={this.focus}
                         url={this.pdfUrl!.url.pathname}
                         isContentActive={this.isPdfContentActive}
@@ -510,22 +604,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         crop={this.crop}
                     />
                 </div>
-                <div style={{ position: 'absolute', height: '100%', right: 0, top: 0, width: `calc(100 * ${this.sidebarWidth() / this.props.PanelWidth()}%` }}>
-                    <SidebarAnnos
-                        ref={this._sidebarRef}
-                        {...this.props}
-                        rootDoc={this.rootDoc}
-                        layoutDoc={this.layoutDoc}
-                        dataDoc={this.dataDoc}
-                        setHeight={emptyFunction}
-                        nativeWidth={this._previewNativeWidth ?? NumCast(this.layoutDoc._nativeWidth)}
-                        showSidebar={this.SidebarShown}
-                        whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
-                        sidebarAddDocument={this.sidebarAddDocument}
-                        moveDocument={this.moveDocument}
-                        removeDocument={this.removeDocument}
-                    />
-                </div>
+                <div style={{ position: 'absolute', height: '100%', right: 0, top: 0, width: `calc(100 * ${this.sidebarWidth() / this.props.PanelWidth()}%` }}>{this.sidebarCollection}</div>
                 {this.settingsPanel()}
             </div>
         );
@@ -535,21 +614,17 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     static pdfpromise = new Map<string, Promise<Pdfjs.PDFDocumentProxy>>();
     render() {
         TraceMobx();
-        if (this._pdf) {
-            if (!this.props.thumbShown?.()) {
-                return this.renderPdfView;
-            }
-            return null;
-        }
+        if (this.props.thumbShown?.()) return null;
+        const pdfView = this.renderPdfView;
 
         const href = this.pdfUrl?.url.href;
-        if (href) {
+        if (!pdfView && href) {
             if (PDFBox.pdfcache.get(href)) setTimeout(action(() => (this._pdf = PDFBox.pdfcache.get(href))));
             else {
                 if (!PDFBox.pdfpromise.get(href)) PDFBox.pdfpromise.set(href, Pdfjs.getDocument(href).promise);
                 PDFBox.pdfpromise.get(href)?.then(action((pdf: any) => PDFBox.pdfcache.set(href, (this._pdf = pdf))));
             }
         }
-        return this.renderTitleBox;
+        return pdfView ?? this.renderTitleBox;
     }
 }
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 61e4894f0..db11a7776 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -11,7 +11,7 @@ import { ComputedField } from '../../../fields/ScriptField';
 import { Cast, NumCast } from '../../../fields/Types';
 import { AudioField, VideoField } from '../../../fields/URLField';
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, OmitKeys, returnFalse, returnOne } from '../../../Utils';
+import { emptyFunction, returnFalse, returnOne, returnZero } from '../../../Utils';
 import { DocUtils } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { Networking } from '../../Network';
@@ -277,7 +277,6 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
         dictationTextProto.mediaState = ComputedField.MakeFunction('self.recordingSource.mediaState');
         this.dataDoc[this.fieldKey + '-dictation'] = dictationText;
     };
-    contentFunc = () => [this.threed, this.content];
     videoPanelHeight = () => (NumCast(this.dataDoc[this.fieldKey + '-nativeHeight'], this.layoutDoc[HeightSym]()) / NumCast(this.dataDoc[this.fieldKey + '-nativeWidth'], this.layoutDoc[WidthSym]())) * this.props.PanelWidth();
     formattedPanelHeight = () => Math.max(0, this.props.PanelHeight() - this.videoPanelHeight());
     render() {
@@ -287,7 +286,10 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                 <div className="videoBox-viewer">
                     <div style={{ position: 'relative', height: this.videoPanelHeight() }}>
                         <CollectionFreeFormView
-                            {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight']).omit}
+                            {...this.props}
+                            setContentView={emptyFunction}
+                            NativeWidth={returnZero}
+                            NativeHeight={returnZero}
                             PanelHeight={this.videoPanelHeight}
                             PanelWidth={this.props.PanelWidth}
                             focus={this.props.focus}
@@ -296,6 +298,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                             select={emptyFunction}
                             isContentActive={returnFalse}
                             NativeDimScaling={returnOne}
+                            isAnyChildContentActive={returnFalse}
                             whenChildContentsActiveChanged={emptyFunction}
                             removeDocument={returnFalse}
                             moveDocument={returnFalse}
@@ -304,17 +307,19 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                             ScreenToLocalTransform={this.props.ScreenToLocalTransform}
                             renderDepth={this.props.renderDepth + 1}
                             ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
-                            {this.contentFunc}
+                            <>
+                                {this.threed}
+                                {this.content}
+                            </>
                         </CollectionFreeFormView>
                     </div>
                     <div style={{ position: 'relative', height: this.formattedPanelHeight() }}>
                         {!(this.dataDoc[this.fieldKey + '-dictation'] instanceof Doc) ? null : (
                             <FormattedTextBox
-                                {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight']).omit}
+                                {...this.props}
                                 Document={this.dataDoc[this.fieldKey + '-dictation']}
                                 fieldKey={'text'}
                                 PanelHeight={this.formattedPanelHeight}
-                                isAnnotationOverlay={true}
                                 select={emptyFunction}
                                 isContentActive={emptyFunction}
                                 NativeDimScaling={returnOne}
@@ -324,7 +329,6 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                                 removeDocument={returnFalse}
                                 moveDocument={returnFalse}
                                 addDocument={returnFalse}
-                                CollectionView={undefined}
                                 renderDepth={this.props.renderDepth + 1}
                                 ContainingCollectionDoc={this.props.ContainingCollectionDoc}></FormattedTextBox>
                         )}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 0b88f5fe3..0570c7fcb 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -9,7 +9,7 @@ import { List } from '../../../fields/List';
 import { ObjectField } from '../../../fields/ObjectField';
 import { Cast, NumCast, StrCast } from '../../../fields/Types';
 import { AudioField, ImageField, VideoField } from '../../../fields/URLField';
-import { emptyFunction, formatTime, OmitKeys, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../Utils';
+import { emptyFunction, formatTime, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { Networking } from '../../Network';
@@ -894,8 +894,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     playing = () => this._playing;
 
-    contentFunc = () => [this.youtubeVideoId ? this.youtubeContent : this.content];
-
     scaling = () => this.props.NativeDimScaling?.() || 1;
 
     panelWidth = () => (this.props.PanelWidth() * this.heightPercent) / 100;
@@ -1068,7 +1066,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                             left: (this.props.PanelWidth() - this.panelWidth()) / 2,
                         }}>
                         <CollectionFreeFormView
-                            {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
+                            {...this.props}
+                            setContentView={emptyFunction}
+                            NativeWidth={returnZero}
+                            NativeHeight={returnZero}
                             renderDepth={this.props.renderDepth + 1}
                             fieldKey={this.annotationKey}
                             CollectionView={undefined}
@@ -1076,6 +1077,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                             annotationLayerHostsContent={true}
                             PanelWidth={this.panelWidth}
                             PanelHeight={this.panelHeight}
+                            isAnyChildContentActive={returnFalse}
                             ScreenToLocalTransform={this.screenToLocalTransform}
                             docFilters={this.timelineDocFilter}
                             select={emptyFunction}
@@ -1084,7 +1086,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                             removeDocument={this.removeDocument}
                             moveDocument={this.moveDocument}
                             addDocument={this.addDocWithTimecode}>
-                            {this.contentFunc}
+                            {this.youtubeVideoId ? this.youtubeContent : this.content}
                         </CollectionFreeFormView>
                     </div>
                     {this.annotationLayer}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index d57518a8d..66d0fd385 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -11,7 +11,7 @@ import { listSpec } from '../../../fields/Schema';
 import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types';
 import { ImageField, WebField } from '../../../fields/URLField';
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, getWordAtPoint, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, smoothScroll, StopEvent, Utils } from '../../../Utils';
+import { emptyFunction, getWordAtPoint, returnFalse, returnOne, returnZero, setupMoveUpEvents, smoothScroll, StopEvent, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager } from '../../util/DragManager';
@@ -305,7 +305,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             const scrollTo = Utils.scrollIntoView(NumCast(anchor.y), anchor[HeightSym](), NumCast(this.layoutDoc._scrollTop), windowHeight, windowHeight * 0.1, Math.max(NumCast(anchor.y) + anchor[HeightSym](), this._scrollHeight));
             if (scrollTo !== undefined) {
                 if (this._initialScroll === undefined) {
-                    this.goTo(scrollTo, options.zoomTime ?? 500, options.easeFunc);
+                    const focusTime = options.zoomTime ?? 500;
+                    this.goTo(scrollTo, focusTime, options.easeFunc);
+                    return focusTime;
                 } else {
                     this._initialScroll = scrollTo;
                 }
@@ -904,9 +906,12 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
         const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this.props.pointerEvents?.() as any);
         const scale = previewScale * (this.props.NativeDimScaling?.() || 1);
-        const renderAnnotations = (docFilters?: () => string[]) => (
+        const renderAnnotations = (docFilters: () => string[]) => (
             <CollectionFreeFormView
-                {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
+                {...this.props}
+                setContentView={emptyFunction}
+                NativeWidth={returnZero}
+                NativeHeight={returnZero}
                 renderDepth={this.props.renderDepth + 1}
                 isAnnotationOverlay={true}
                 fieldKey={this.annotationKey}
@@ -921,6 +926,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 dropAction={'alias'}
                 docFilters={docFilters}
                 select={emptyFunction}
+                isAnyChildContentActive={returnFalse}
                 bringToFront={emptyFunction}
                 styleProvider={this.childStyleProvider}
                 whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index ee4249b02..d8afc3227 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -20,7 +20,7 @@ import { RichTextUtils } from '../../../../fields/RichTextUtils';
 import { ComputedField } from '../../../../fields/ScriptField';
 import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
 import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils';
 import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils';
 import { DocServer } from '../../../DocServer';
 import { Docs, DocUtils } from '../../../documents/Documents';
@@ -1739,12 +1739,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             }
         }
     };
-    fitContentsToBox = () => this.props.Document._fitContentsToBox;
+    fitContentsToBox = () => BoolCast(this.props.Document._fitContentsToBox);
     sidebarContentScaling = () => (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
     sidebarAddDocument = (doc: Doc | Doc[], sidebarKey: string = this.SidebarKey) => {
         if (!this.layoutDoc._showSidebar) this.toggleSidebar();
-        // console.log("printting allSideBarDocs");
-        // console.log(this.allSidebarDocs);
         return this.addDocument(doc, sidebarKey);
     };
     sidebarMoveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.moveDocument(doc, targetCollection, addDocument, this.SidebarKey);
@@ -1785,8 +1783,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 className="formattedTextBox-sidebar-handle"
                 onPointerDown={this.sidebarDown}
                 style={{
-                    backgroundColor: backgroundColor,
-                    color: color,
+                    backgroundColor,
+                    color,
                     opacity: annotated ? 1 : undefined,
                 }}>
                 <FontAwesomeIcon icon={'comment-alt'} />
@@ -1800,33 +1798,36 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 <SidebarAnnos
                     ref={this._sidebarRef}
                     {...this.props}
-                    fieldKey={this.fieldKey}
                     rootDoc={this.rootDoc}
                     layoutDoc={this.layoutDoc}
                     dataDoc={this.dataDoc}
-                    ScreenToLocalTransform={this.sidebarScreenToLocal}
+                    usePanelWidth={true}
                     nativeWidth={NumCast(this.layoutDoc._nativeWidth)}
-                    whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                     showSidebar={this.SidebarShown}
-                    PanelWidth={this.sidebarWidth}
-                    setHeight={this.setSidebarHeight}
+                    whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                     sidebarAddDocument={this.sidebarAddDocument}
                     moveDocument={this.moveDocument}
                     removeDocument={this.removeDocument}
+                    ScreenToLocalTransform={this.sidebarScreenToLocal}
+                    fieldKey={this.fieldKey}
+                    PanelWidth={this.sidebarWidth}
+                    setHeight={this.setSidebarHeight}
                 />
             ) : (
                 <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.props.DocumentView?.()!, false), true)}>
                     <ComponentTag
-                        {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
+                        {...this.props}
+                        setContentView={emptyFunction}
                         NativeWidth={returnZero}
                         NativeHeight={returnZero}
                         PanelHeight={this.props.PanelHeight}
                         PanelWidth={this.sidebarWidth}
                         xPadding={0}
                         yPadding={0}
-                        scaleField={this.SidebarKey + '-scale'}
+                        viewField={this.SidebarKey}
                         isAnnotationOverlay={false}
                         select={emptyFunction}
+                        isAnyChildContentActive={returnFalse}
                         NativeDimScaling={this.sidebarContentScaling}
                         whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                         removeDocument={this.sidebarRemDocument}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index c5060a2c2..6ab541207 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -7,7 +7,7 @@ import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { Cast, NumCast, StrCast } from '../../../fields/Types';
 import { TraceMobx } from '../../../fields/util';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, OmitKeys, returnNone, smoothScroll, Utils } from '../../../Utils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, returnAll, returnFalse, returnNone, returnTrue, returnZero, smoothScroll, Utils } from '../../../Utils';
 import { DocUtils } from '../../documents/Documents';
 import { DragManager } from '../../util/DragManager';
 import { SelectionManager } from '../../util/SelectionManager';
@@ -16,7 +16,7 @@ import { SnappingManager } from '../../util/SnappingManager';
 import { MarqueeOptionsMenu } from '../collections/collectionFreeForm';
 import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
 import { MarqueeAnnotator } from '../MarqueeAnnotator';
-import { DocFocusOptions, DocumentViewProps, OpenWhere } from '../nodes/DocumentView';
+import { DocFocusOptions, DocumentViewProps } from '../nodes/DocumentView';
 import { FieldViewProps } from '../nodes/FieldView';
 import { LinkDocPreview } from '../nodes/LinkDocPreview';
 import { StyleProp } from '../StyleProvider';
@@ -512,7 +512,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         return this.props.styleProvider?.(doc, props, property);
     };
 
-    renderAnnotations = (docFilters?: () => string[], mixBlendMode?: any, display?: string) => (
+    renderAnnotations = (docFilters: () => string[], mixBlendMode?: any, display?: string) => (
         <div
             className="pdfViewerDash-overlay"
             style={{
@@ -522,9 +522,12 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 pointerEvents: Doc.ActiveTool !== InkTool.None ? 'all' : undefined,
             }}>
             <CollectionFreeFormView
-                {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
+                {...this.props}
+                NativeWidth={returnZero}
+                NativeHeight={returnZero}
+                setContentView={emptyFunction} // override setContentView to do nothing
+                pointerEvents={SnappingManager.GetIsDragging() ? returnAll : returnNone}
                 renderDepth={this.props.renderDepth + 1}
-                pointerEvents={returnNone}
                 isAnnotationOverlay={true}
                 fieldKey={this.props.fieldKey + '-annotations'}
                 CollectionView={undefined}
@@ -534,6 +537,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 PanelHeight={this.panelHeight}
                 PanelWidth={this.panelWidth}
                 ScreenToLocalTransform={this.overlayTransform}
+                isAnyChildContentActive={returnFalse}
+                isAnnotationOverlayScrollable={true}
                 dropAction={'alias'}
                 docFilters={docFilters}
                 select={emptyFunction}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 553c4525c..cc024d83a 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1213,7 +1213,7 @@ export namespace Doc {
         return doc[StrCast(doc.layoutKey, 'layout')];
     }
     export function LayoutFieldKey(doc: Doc): string {
-        return StrCast(Doc.Layout(doc).layout).split("'")[1];
+        return StrCast(Doc.Layout(doc)[StrCast(doc.layoutKey, 'layout')]).split("'")[1]; // bcz: TODO check on this .  used to always reference 'layout', now it uses the layout speicfied by the current layoutKey
     }
     export function NativeAspect(doc: Doc, dataDoc?: Doc, useDim?: boolean) {
         return Doc.NativeWidth(doc, dataDoc, useDim) / (Doc.NativeHeight(doc, dataDoc, useDim) || 1);
@@ -1222,9 +1222,10 @@ export namespace Doc {
         return !doc ? 0 : NumCast(doc._nativeWidth, NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '-nativeWidth'], useWidth ? doc[WidthSym]() : 0));
     }
     export function NativeHeight(doc?: Doc, dataDoc?: Doc, useHeight?: boolean) {
-        const dheight = doc ? NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '-nativeHeight'], useHeight ? doc[HeightSym]() : 0) : 0;
-        const nheight = doc ? (Doc.NativeWidth(doc, dataDoc, useHeight) * doc[HeightSym]()) / doc[WidthSym]() : 0;
-        return !doc ? 0 : NumCast(doc._nativeHeight, nheight || dheight);
+        if (!doc) return 0;
+        const nheight = (Doc.NativeWidth(doc, dataDoc, useHeight) * doc[HeightSym]()) / doc[WidthSym]();
+        const dheight = NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '-nativeHeight'], useHeight ? doc[HeightSym]() : 0);
+        return NumCast(doc._nativeHeight, nheight || dheight);
     }
     export function SetNativeWidth(doc: Doc, width: number | undefined, fieldKey?: string) {
         doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + '-nativeWidth'] = width;
-- 
cgit v1.2.3-70-g09d2

