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/SchemaTableCell.tsx           | 24 ++++++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 src/client/views/collections/collectionSchema/SchemaTableCell.tsx

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

diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
new file mode 100644
index 000000000..1eb5e0e01
--- /dev/null
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -0,0 +1,24 @@
+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 {
+    Document: Doc;
+    fieldKey: string;
+    columnWidth: number;
+}
+
+@observer
+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 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/SchemaTableCell.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 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/SchemaTableCell.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 222f659b8c291fafce2648e367392dd9f467cb25 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 27 Feb 2023 17:00:49 -0500
Subject: rows are documentviews but clipped

---
 package-lock.json                                  |  39 +++++++
 .../collectionSchema/CollectionSchemaView.scss     |   6 ++
 .../collectionSchema/CollectionSchemaView.tsx      |  96 ++++++++++++-----
 .../collections/collectionSchema/SchemaRowBox.tsx  | 120 ++++++++++++---------
 .../collectionSchema/SchemaTableCell.tsx           |  12 ++-
 src/client/views/nodes/DocumentContentsView.tsx    |   2 +
 6 files changed, 195 insertions(+), 80 deletions(-)

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

diff --git a/package-lock.json b/package-lock.json
index 3c2dccbf8..8806887df 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5308,6 +5308,16 @@
             "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
             "dev": true
         },
+        "d": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+            "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+            "dev": true,
+            "requires": {
+                "es5-ext": "^0.10.50",
+                "type": "^1.0.1"
+            }
+        },
         "d3-array": {
             "version": "2.12.1",
             "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
@@ -6475,6 +6485,28 @@
                 "is-symbol": "^1.0.2"
             }
         },
+        "es5-ext": {
+            "version": "0.10.62",
+            "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
+            "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
+            "dev": true,
+            "requires": {
+                "es6-iterator": "^2.0.3",
+                "es6-symbol": "^3.1.3",
+                "next-tick": "^1.1.0"
+            }
+        },
+        "es6-iterator": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+            "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+            "dev": true,
+            "requires": {
+                "d": "1",
+                "es5-ext": "^0.10.35",
+                "es6-symbol": "^3.1.1"
+            }
+        },
         "es6-promise": {
             "version": "3.2.1",
             "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz",
@@ -6486,6 +6518,7 @@
             "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
             "dev": true,
             "requires": {
+                "d": "^1.0.1",
                 "ext": "^1.1.2"
             }
         },
@@ -21371,6 +21404,12 @@
             "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
             "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
         },
+        "type": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+            "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==",
+            "dev": true
+        },
         "type-check": {
             "version": "0.3.2",
             "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index bd0fc11b3..46c2e2d1a 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -134,10 +134,16 @@
     }
 }
 
+.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 64c39cf1a..46510b6fe 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, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents, smoothScroll, Utils } from '../../../../Utils';
 import { Docs, DocUtils } from '../../../documents/Documents';
 import { DragManager } from '../../../util/DragManager';
 import { SelectionManager } from '../../../util/SelectionManager';
@@ -17,7 +17,7 @@ import { undoBatch } from '../../../util/UndoManager';
 import { ContextMenu } from '../../ContextMenu';
 import { ContextMenuProps } from '../../ContextMenuItem';
 import { EditableView } from '../../EditableView';
-import { DocumentView } from '../../nodes/DocumentView';
+import { DocFocusOptions, DocumentView, ViewAdjustment } from '../../nodes/DocumentView';
 import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
 import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
@@ -41,9 +41,9 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _lastSelectedRow: number | undefined;
     private _selectedDocSortedArray: Doc[] = [];
     private _closestDropIndex: number = 0;
-    private _minColWidth: number = 150;
     private _previewRef: HTMLDivElement | null = null;
 
+    public static _minColWidth: number = 150;
     public static _rowMenuWidth: number = 100;
     public static _previewDividerWidth: number = 4;
     @observable _selectedDocs: ObservableSet = new ObservableSet<Doc>();
@@ -110,6 +110,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     componentDidMount() {
+        this.props.setContentView?.(this);
         document.addEventListener('keydown', this.onKeyDown);
     }
 
@@ -243,8 +244,8 @@ export class CollectionSchemaView extends CollectionSubView() {
             if (shrinking === undefined || growing === undefined) return true;
 
             change = Math.abs(change);
-            if (this._displayColumnWidths[shrinking] - change < this._minColWidth) {
-                change = this._displayColumnWidths[shrinking] - this._minColWidth;
+            if (this._displayColumnWidths[shrinking] - change < CollectionSchemaView._minColWidth) {
+                change = this._displayColumnWidths[shrinking] - CollectionSchemaView._minColWidth;
             }
 
             this._displayColumnWidths[shrinking] -= change;
@@ -481,7 +482,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         !Doc.noviceMode && ContextMenu.Instance.addItem({ description: 'Containers ...', subitems: layoutItems, icon: 'eye' });
         ContextMenu.Instance.setDefaultItem('::', (name: string): void => {
             Doc.GetProto(this.props.Document)[name] = '';
-            const created = Docs.Create.TextDocument('', { title: name, _width: 250, _autoHeight: true });
+            const created = Docs.Create.TextDocument('', { title: name, _autoHeight: true });
             if (created) {
                 if (this.props.Document.isTemplateDoc) {
                     Doc.MakeMetadataFieldTemplate(created, this.props.Document);
@@ -492,9 +493,25 @@ 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;
-
     getDocTransform(doc: Doc, dref?: DocumentView) {
         const { scale, translateX, translateY } = Utils.GetScreenTransform(dref?.ContentDiv || undefined);
         // the document view may center its contents and if so, will prepend that onto the screenToLocalTansform.  so we have to subtract that off
@@ -543,26 +560,55 @@ export class CollectionSchemaView extends CollectionSubView() {
                         {this.childDocs.map((doc: Doc, index: number) => {
                             const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.DataDoc;
                             let dref: Opt<DocumentView>;
-
                             return (
-                                <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 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.tableWidth}
+                                        PanelHeight={() => 70}
+                                        styleProvider={DefaultStyleProvider}
+                                        focus={this.focusDocument}
+                                        docFilters={this.childDocFilters}
+                                        docViewPath={this.props.docViewPath}
+                                        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>
                             );
+                            // return (
+                            //     <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>
                     <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} />
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 2cf0a1b79..0378fa67e 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -1,17 +1,17 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, ObservableSet } from 'mobx';
+import { computed, ObservableSet } from 'mobx';
 import { observer } from 'mobx-react';
 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 { OpenWhere } from '../../nodes/DocumentView';
-import { FieldViewProps } from '../../nodes/FieldView';
+import { FieldView, FieldViewProps } from '../../nodes/FieldView';
+import { CollectionSchemaView } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
-import { setupMoveUpEvents, emptyFunction } from '../../../../Utils';
+import { Colors } from '../../global/globalEnums';
+import { DocCast, StrCast } from '../../../../fields/Types';
 
 export interface SchemaRowBoxProps extends FieldViewProps {
     rowIndex: number;
@@ -27,79 +27,93 @@ export interface SchemaRowBoxProps extends FieldViewProps {
 }
 
 @observer
-export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
+export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
+    public static LayoutString(fieldKey: string) {
+        return FieldView.LayoutString(SchemaRowBox, fieldKey);
+    }
+
     private _ref: HTMLDivElement | null = null;
 
     bounds = () => this._ref?.getBoundingClientRect();
 
-    isSelected = () => this.props.selectedDocs.has(this.props.Document);
+    @computed get schemaView() {
+        const vpath = this.props.docViewPath();
+        console.log(vpath[vpath.length - 2]);
+        return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as CollectionSchemaView) : undefined;
+    }
 
-    @action
-    onRowPointerDown = (e: React.PointerEvent) => {
-        e.stopPropagation();
+    @computed get schemaDoc() {
+        return this.props.ContainingCollectionDoc!;
+    }
 
-        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)
-        );
-    };
+    // isSelected = () => this.props.selectedDocs.has(this.props.Document);
 
-    onPointerEnter = (e: any) => {
-        if (!this.props.dragging) return;
-        document.removeEventListener('pointermove', this.onPointerMove);
-        document.addEventListener('pointermove', this.onPointerMove);
-    };
+    // @action
+    // onRowPointerDown = (e: React.PointerEvent) => {
+    //     e.stopPropagation();
 
-    onPointerMove = (e: any) => {
-        if (!this.props.dragging) return;
-        let dragIsRow: boolean = true;
-        DragManager.docsBeingDragged.forEach(doc => {
-            dragIsRow = this.props.selectedDocs.has(doc);
-        });
-        if (this._ref && dragIsRow) {
-            const rect = this._ref.getBoundingClientRect();
-            const y = e.clientY - rect.top; //y position within the element.
-            const height = this._ref.clientHeight;
-            const halfLine = height / 2;
-            if (y <= halfLine) {
-                this._ref.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
-                this._ref.style.borderBottom = '0px';
-                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);
-            }
-        }
-    };
+    //     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;
+    //     document.removeEventListener('pointermove', this.onPointerMove);
+    //     document.addEventListener('pointermove', this.onPointerMove);
+    // };
+
+    // onPointerMove = (e: any) => {
+    //     if (!this.props.dragging) return;
+    //     let dragIsRow: boolean = true;
+    //     DragManager.docsBeingDragged.forEach(doc => {
+    //         dragIsRow = this.props.selectedDocs.has(doc);
+    //     });
+    //     if (this._ref && dragIsRow) {
+    //         const rect = this._ref.getBoundingClientRect();
+    //         const y = e.clientY - rect.top; //y position within the element.
+    //         const height = this._ref.clientHeight;
+    //         const halfLine = height / 2;
+    //         if (y <= halfLine) {
+    //             this._ref.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
+    //             this._ref.style.borderBottom = '0px';
+    //             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);
+    //         }
+    //     }
+    // };
 
     onPointerLeave = (e: any) => {
         if (this._ref) {
             this._ref.style.borderTop = '0px';
             this._ref.style.borderBottom = '0px';
         }
-        document.removeEventListener('pointermove', this.onPointerMove);
+        // document.removeEventListener('pointermove', this.onPointerMove);
     };
 
     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}
+                style={this.props.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,
+                        width: CollectionSchemaView._rowMenuWidth,
                     }}>
                     <div
                         className="schema-row-button"
@@ -119,8 +133,8 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                     </div>
                 </div>
                 <div className="row-cells">
-                    {this.props.columnKeys.map((key, index) => (
-                        <SchemaTableCell key={key} Document={this.props.Document} fieldKey={key} columnWidth={this.props.columnWidths[index]} />
+                    {this.schemaView?.columnKeys?.map((key, index) => (
+                        <SchemaTableCell key={key} Document={this.props.Document} fieldKey={key} columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth} />
                     ))}
                 </div>
             </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 5d9474173..e2f6d99f1 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -1,7 +1,14 @@
 import React = require('react');
 import { observer } from 'mobx-react';
-import { Doc, Field } from '../../../../fields/Doc';
+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 { EditableView } from '../../EditableView';
+import { MAX_ROW_HEIGHT } from '../../global/globalCssVariables.scss';
 
 export interface SchemaTableCellProps {
     Document: Doc;
@@ -14,7 +21,8 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     render() {
         return (
             <div className="schema-table-cell" style={{ width: this.props.columnWidth }}>
-                {Field.toString(this.props.Document[this.props.fieldKey] as Field)}
+                {/* {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} />
             </div>
         );
     }
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 569579996..459554ebe 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -44,6 +44,7 @@ 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?
 
@@ -268,6 +269,7 @@ export class DocumentContentsView extends React.Component<
                     HTMLtag,
                     ComparisonBox,
                     LoadingBox,
+                    SchemaRowBox,
                 }}
                 bindings={bindings}
                 jsx={layoutFrame}
-- 
cgit v1.2.3-70-g09d2


From df4781b27848731b329068b13da89a17d04ad1a9 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Tue, 28 Feb 2023 17:13:11 -0500
Subject: selection working (except ctrl+click)

---
 .../collectionSchema/CollectionSchemaView.tsx      | 157 ++++++++++-----------
 .../collections/collectionSchema/SchemaRowBox.tsx  |  56 ++++----
 .../collectionSchema/SchemaTableCell.tsx           |   4 +-
 3 files changed, 102 insertions(+), 115 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index bd9303997..22b8496aa 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -6,7 +6,7 @@ import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { RichTextField } from '../../../../fields/RichTextField';
 import { listSpec } from '../../../../fields/Schema';
-import { BoolCast, Cast, NumCast, StrCast } from '../../../../fields/Types';
+import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents, smoothScroll, Utils } from '../../../../Utils';
 import { Docs, DocUtils } from '../../../documents/Documents';
@@ -24,6 +24,7 @@ import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
+import { DocumentManager } from '../../../util/DocumentManager';
 
 export enum ColumnType {
     Number,
@@ -38,7 +39,6 @@ const defaultColumnKeys: string[] = ['title', 'type', 'author', 'creationDate',
 @observer
 export class CollectionSchemaView extends CollectionSubView() {
     private _ref: HTMLDivElement | null = null;
-    private _lastSelectedRow: number | undefined;
     private _selectedDocSortedArray: Doc[] = [];
     private _closestDropIndex: number = 0;
     private _previewRef: HTMLDivElement | null = null;
@@ -47,11 +47,11 @@ export class CollectionSchemaView extends CollectionSubView() {
     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 _previewDoc: Doc | undefined;
 
     get documentKeys() {
         const docs = this.childDocs;
@@ -110,6 +110,10 @@ export class CollectionSchemaView extends CollectionSubView() {
         return BoolCast(this.layoutDoc.sortDesc);
     }
 
+    rowIndex(doc: Doc) {
+        return this.childDocs.indexOf(doc);
+    }
+
     componentDidMount() {
         this.props.setContentView?.(this as DocComponentView);
         document.addEventListener('keydown', this.onKeyDown);
@@ -121,30 +125,32 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @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;
-                }
-            }
-        }
+        // 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);
+        //             const presDocView = DocumentManager.Instance.getDocumentView(this.rootDoc);
+        //         if (presDocView) SelectionManager.SelectView(presDocView, false);
+        //             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
@@ -304,40 +310,51 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     @action
-    selectRow = (e: React.PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => {
+    addDocToSelection = (doc: Doc, extendSelection: boolean, index: number) => {
+        this._selectedDocs.add(doc);
+        const rowDocView = DocumentManager.Instance.getDocumentView(doc);
+        if (rowDocView) SelectionManager.SelectView(rowDocView, extendSelection);
+        this._lastSelectedRow = index;
+    };
+
+    @action
+    removeDocFromSelection = (doc: Doc) => {
+        if (this._selectedDocs.has(doc)) this._selectedDocs.delete(doc);
+        const rowDocView = DocumentManager.Instance.getDocumentView(doc);
+        if (rowDocView) SelectionManager.DeselectView(rowDocView);
+    };
+
+    @action
+    clearSelection = () => {
+        this._selectedDocs.clear();
+        SelectionManager.DeselectAll();
+        this._lastSelectedRow = undefined;
+    };
+
+    @action
+    selectRow = (e: PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => {
+        e.stopPropagation();
+        if (index < 0) return;
         const ctrl = e.ctrlKey || e.metaKey;
         const shift = e.shiftKey;
         if (shift && this._lastSelectedRow !== undefined) {
             const startRow = Math.min(this._lastSelectedRow, index);
             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.add(currDoc);
+                this.addDocToSelection(this.childDocs[i], true, i);
             }
-            this._lastSelectedRow = endRow;
+            this._lastSelectedRow = index;
         } else if (ctrl) {
             if (!this._selectedDocs.has(doc)) {
-                this._selectedDocs.add(doc);
-                this._lastSelectedRow = index;
+                console.log('add');
+                this.addDocToSelection(doc, true, index);
             } else {
-                this._selectedDocs.delete(doc);
+                console.log('remove');
+                this.removeDocFromSelection(doc);
             }
         } else {
-            this._selectedDocs.clear();
-            this._selectedDocs.add(doc);
-            this._lastSelectedRow = index;
-        }
-
-        if (this._lastSelectedRow && this._selectedDocs.size > 0) {
-            SelectionManager.SelectSchemaViewDoc(this.childDocs[this._lastSelectedRow]);
-        } else {
-            SelectionManager.SelectSchemaViewDoc(undefined);
-        }
-
-        if (this._selectedDocs.size == 1) {
-            this._previewDoc = Array.from(this._selectedDocs)[0];
-        } else {
-            this._previewDoc = undefined;
+            this.clearSelection();
+            this.addDocToSelection(doc, false, index);
         }
     };
 
@@ -381,10 +398,8 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     startDrag = (e: React.PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => {
         if (!this._selectedDocs.has(doc)) {
-            this._selectedDocs.clear();
-            this._selectedDocs.add(doc);
-            this._lastSelectedRow = index;
-            SelectionManager.SelectSchemaViewDoc(doc);
+            this.clearSelection();
+            this.addDocToSelection(doc, false, index);
         }
         this._isDragging = true;
         this._selectedDocSortedArray = this.sortedSelectedDocs();
@@ -511,13 +526,9 @@ export class CollectionSchemaView extends CollectionSubView() {
             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;
-    getDocTransform(doc: Doc, dref?: DocumentView) {
-        const { scale, translateX, translateY } = Utils.GetScreenTransform(dref?.ContentDiv || undefined);
-        // the document view may center its contents and if so, will prepend that onto the screenToLocalTansform.  so we have to subtract that off
-        return new Transform(-translateX + (dref?.centeringX || 0), -translateY + (dref?.centeringY || 0), 1).scale(this.props.ScreenToLocalTransform().Scale);
-    }
 
     render() {
         return (
@@ -531,9 +542,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                 <div
                     className="schema-table"
                     onPointerDown={action(() => {
-                        this._selectedDocs.clear();
-                        SelectionManager.SelectSchemaViewDoc(undefined);
-                        this._previewDoc = undefined;
+                        this.clearSelection();
                     })}>
                     <div className="schema-header-row" style={{ height: CollectionSchemaView._rowHeight }}>
                         <div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}></div>
@@ -552,7 +561,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                                     addColumn={this.addColumn}
                                     removeColumn={this.removeColumn}
                                     resizeColumn={this.startResize}
-                                    // dragColumn={this.dragColumn}
                                 />
                             );
                         })}
@@ -568,7 +576,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                                         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}
@@ -578,7 +585,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                                         styleProvider={DefaultStyleProvider}
                                         focus={this.focusDocument}
                                         docFilters={this.childDocFilters}
-                                        docViewPath={this.props.docViewPath}
                                         docRangeFilters={this.childDocRangeFilters}
                                         searchFilterDocs={this.searchFilterDocs}
                                         rootSelected={this.rootSelected}
@@ -592,25 +598,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                                     />
                                 </div>
                             );
-                            // return (
-                            //     <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>
                     <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} />
@@ -618,9 +605,9 @@ export class CollectionSchemaView extends CollectionSubView() {
                 {this.previewWidth > 0 && <div className="schema-preview-divider" style={{ width: CollectionSchemaView._previewDividerWidth }} onPointerDown={this.onDividerDown}></div>}
                 {this.previewWidth > 0 && (
                     <div style={{ width: `${this.previewWidth}px` }} ref={ref => (this._previewRef = ref)}>
-                        {this._previewDoc && (
+                        {this._lastSelectedRow !== undefined && (
                             <DocumentView
-                                Document={this._previewDoc}
+                                Document={this.childDocs[this._lastSelectedRow]}
                                 DataDoc={undefined}
                                 fitContentsToBox={returnTrue}
                                 dontCenter={'y'}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index e72ed3c4f..d67e6f2d7 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -1,6 +1,6 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { computed, ObservableSet } from 'mobx';
+import { action, computed, ObservableSet } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc } from '../../../../fields/Doc';
 import { undoBatch } from '../../../util/UndoManager';
@@ -12,19 +12,7 @@ import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
 import { Colors } from '../../global/globalEnums';
 import { DocCast, StrCast } from '../../../../fields/Types';
-
-export interface SchemaRowBoxProps extends FieldViewProps {
-    rowIndex: number;
-    columnKeys: string[];
-    columnWidths: number[];
-    rowMenuWidth: number;
-    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;
-}
+import { setupMoveUpEvents, emptyFunction } from '../../../../Utils';
 
 @observer
 export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -38,7 +26,6 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
 
     @computed get schemaView() {
         const vpath = this.props.docViewPath();
-        console.log(vpath[vpath.length - 2]);
         return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as CollectionSchemaView) : undefined;
     }
 
@@ -46,20 +33,25 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return this.props.ContainingCollectionDoc!;
     }
 
+    @computed get rowIndex() {
+        return this.schemaView?.rowIndex(this.rootDoc) ?? -1;
+    }
+
     // isSelected = () => this.props.selectedDocs.has(this.props.Document);
 
-    // @action
-    // onRowPointerDown = (e: React.PointerEvent) => {
-    //     e.stopPropagation();
+    @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.schemaView?.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex) ?? true,
+            returnTrue,
+            emptyFunction,
+            e => this.schemaView?.selectRow(e, this.props.Document, this._ref!, this.rowIndex)
+        );
+    };
 
     // onPointerEnter = (e: any) => {
     //     if (!this.props.dragging) return;
@@ -102,8 +94,12 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return (
             <div
                 className="schema-row"
-                style={this.props.isSelected() ? { height: CollectionSchemaView._rowHeight, backgroundColor: Colors.LIGHT_BLUE /*, opacity: this.props.dragging ? 0.5 : 1 */ } : { height: CollectionSchemaView._rowHeight }}
-                // onPointerDown={this.onRowPointerDown}
+                style={
+                    this.props.isSelected()
+                        ? { height: CollectionSchemaView._rowHeight, backgroundColor: Colors.LIGHT_BLUE, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined /*, opacity: this.props.dragging ? 0.5 : 1 */ }
+                        : { height: CollectionSchemaView._rowHeight, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined }
+                }
+                onPointerDown={this.onRowPointerDown}
                 // onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
@@ -141,3 +137,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         );
     }
 }
+function // e => this.schemaView?.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex) ?? true,
+returnTrue(e: PointerEvent, down: number[], delta: number[]): boolean {
+    throw new Error('Function not implemented.');
+}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index e2f6d99f1..4cfc5850c 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -21,8 +21,8 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     render() {
         return (
             <div className="schema-table-cell" style={{ width: this.props.columnWidth }}>
-                {/* {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} />
+                {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} /> */}
             </div>
         );
     }
-- 
cgit v1.2.3-70-g09d2


From 67a0081bb4fb713b730fa86a5b67d3c061426514 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 1 Mar 2023 21:45:13 -0500
Subject: cells editable

---
 .../collections/collectionSchema/SchemaRowBox.tsx  |  4 +-
 .../collectionSchema/SchemaTableCell.tsx           | 45 +++++++++++++++++++++-
 2 files changed, 45 insertions(+), 4 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 4b709f670..05197d05f 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -93,7 +93,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
-                    row && this.schemaView?.addRowRef(this.rootDoc, row);
+                    row && this.schemaView?.addRowRef?.(this.rootDoc, row);
                     this._ref = row;
                 }}>
                 <div
@@ -120,7 +120,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 </div>
                 <div className="row-cells">
                     {this.schemaView?.columnKeys?.map((key, index) => (
-                        <SchemaTableCell key={key} Document={this.rootDoc} fieldKey={key} columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth} />
+                        <SchemaTableCell key={key} Document={this.rootDoc} fieldKey={key} columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth} isRowActive={this.props.isContentActive} />
                     ))}
                 </div>
             </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 4cfc5850c..0f832e7c4 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -9,20 +9,61 @@ import { FieldValue } from '../../../../fields/Types';
 import { CompileScript } from '../../../util/Scripting';
 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';
 
 export interface SchemaTableCellProps {
     Document: Doc;
     fieldKey: string;
     columnWidth: number;
+    isRowActive: () => boolean | undefined;
 }
 
 @observer
 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,
+            styleProvider: DefaultStyleProvider,
+            docViewPath: returnEmptyDoclist,
+            ContainingCollectionView: undefined,
+            ContainingCollectionDoc: undefined,
+            fieldKey: this.props.fieldKey,
+            rootSelected: returnFalse,
+            isSelected: returnFalse,
+            setHeight: returnFalse,
+            select: emptyFunction,
+            dropAction: 'alias',
+            bringToFront: emptyFunction,
+            renderDepth: 1,
+            isContentActive: returnFalse,
+            whenChildContentsActiveChanged: emptyFunction,
+            ScreenToLocalTransform: Transform.Identity,
+            focus: emptyFunction,
+            PanelWidth: () => this.props.columnWidth,
+            PanelHeight: () => CollectionSchemaView._rowHeight,
+            addDocTab: returnFalse,
+            pinToPres: returnZero,
+        };
+
         return (
-            <div className="schema-table-cell" style={{ width: this.props.columnWidth }}>
-                {Field.toString(this.props.Document[this.props.fieldKey] as Field)}
+            <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'}
+                    GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
+                    SetValue={(value: string) => KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value)}
+                />
             </div>
         );
     }
-- 
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/SchemaTableCell.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 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/SchemaTableCell.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 448b04afae562f9c34bc23379d4ce7d84de579d3 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 22 Mar 2023 16:23:13 -0400
Subject: render filter option dropdown

---
 .../collectionSchema/CollectionSchemaView.tsx      | 50 +++++++++++++++++++++-
 .../collectionSchema/SchemaTableCell.tsx           |  2 +-
 2 files changed, 50 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 0b68fd31e..7a65b4436 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -805,18 +805,66 @@ export class CollectionSchemaView extends CollectionSubView() {
         );
     }
 
+    @computed get renderFilterOptions() {
+        const keyOptions: string[] = [];
+        const columnKey = this.columnKeys[this._filterColumnIndex!];
+        this.childDocs.forEach(doc => {
+            const key = StrCast(doc[columnKey]);
+            if (keyOptions.includes(key) === false && (key.includes(this._filterValue) || !this._filterValue) && key !== '') {
+                keyOptions.push(key);
+            }
+        });
+
+        const filters = StrListCast(this.Document._docFilters);
+        for (let i = 0; i < (filters?.length ?? 0) - 1; i++) {
+            if (filters[i] === columnKey && keyOptions.includes(filters[i].split(':')[1]) === false) {
+                keyOptions.push(filters[i + 1]);
+            }
+        }
+
+        const options = keyOptions.map(key => {
+            let bool = false;
+            if (filters !== undefined) {
+                const ind = filters.findIndex(filter => filter.split(':')[1] === key);
+                const fields = ind === -1 ? undefined : filters[ind].split(':');
+                bool = fields ? fields[2] === 'check' : false;
+            }
+            return (
+                <div key={key} className="schema-filter-option">
+                    <input
+                        type="checkbox"
+                        onPointerDown={e => e.stopPropagation()}
+                        onClick={e => e.stopPropagation()}
+                        onChange={action(e => {
+                            if (e.target.checked) {
+                                Doc.setDocFilter(this.props.Document, columnKey, key, 'check');
+                            } else {
+                                Doc.setDocFilter(this.props.Document, columnKey, key, 'remove');
+                            }
+                        })}
+                        checked={bool}
+                    />
+                    <span style={{ paddingLeft: 4 }}>{key}</span>
+                </div>
+            );
+        });
+
+        return options;
+    }
+
     @computed get renderFilterMenu() {
         const x = this.displayColumnWidths.reduce((total, curr, index) => total + (index < this._filterColumnIndex! ? curr : 0), CollectionSchemaView._rowMenuWidth);
         return (
             <div className="schema-filter-menu" style={{ left: x, minWidth: CollectionSchemaView._minColWidth }}>
                 <input className="schema-filter-input" type="text" value={this._filterValue} onKeyDown={this.onFilterKeyDown} onChange={this.updateFilterSearch} onPointerDown={e => e.stopPropagation()} />
+                {this.renderFilterOptions}
                 <div
                     className="schema-column-menu-button"
                     onPointerDown={action(e => {
                         e.stopPropagation();
                         this.closeFilterMenu();
                     })}>
-                    cancel
+                    done
                 </div>
             </div>
         );
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 91b292b28..d475c3b6f 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -49,7 +49,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
 
         return (
             <div className="schema-table-cell" style={{ width: this.props.columnWidth }}>
-                <div className="schemacell-edit-wrapper" style={{ cursor: this.props.isRowActive() ? 'text' : 'default' }}>
+                <div className="schemacell-edit-wrapper" style={this.props.isRowActive() ? { cursor: 'text', pointerEvents: 'auto' } : { cursor: 'default', pointerEvents: 'none' }}>
                     <EditableView
                         contents={<FieldView {...props} />}
                         GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
-- 
cgit v1.2.3-70-g09d2


From 3fed87fe05a70a5ef63ed7989c7a28faee68bf4b Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 22 Mar 2023 17:42:28 -0400
Subject: shift enter shortcut to fill column

---
 .../views/collections/collectionSchema/CollectionSchemaView.scss | 7 +++----
 .../views/collections/collectionSchema/CollectionSchemaView.tsx  | 7 +++++++
 src/client/views/collections/collectionSchema/SchemaRowBox.tsx   | 9 ++++++++-
 .../views/collections/collectionSchema/SchemaTableCell.tsx       | 8 +++++++-
 4 files changed, 25 insertions(+), 6 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 1853fb589..287e2b01b 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -109,6 +109,8 @@
     align-items: center;
     padding: 0;
     z-index: 1;
+    border: 1px solid $medium-gray;
+    overflow: hidden;
 
     .schema-column-title {
         flex-grow: 2;
@@ -146,7 +148,6 @@
 }
 
 .schema-row-wrapper {
-    // max-height: 70px;
     overflow: hidden;
 }
 
@@ -159,16 +160,14 @@
     display: flex;
     flex-direction: row;
     height: 100%;
-    // max-height: 70px;
     overflow: auto;
 }
 
-.schema-column-header,
 .schema-table-cell,
 .row-menu {
     border: 1px solid $medium-gray;
-    padding: 5px;
     overflow: hidden;
+    padding: 5px;
 }
 
 .schema-row {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 4498a2258..48db1467c 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -28,6 +28,7 @@ import { DocumentManager } from '../../../util/DocumentManager';
 import { ScriptField } from '../../../../fields/ScriptField';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { IconButton } from 'browndash-components';
+import { KeyValueBox } from '../../nodes/KeyValueBox';
 
 export enum ColumnType {
     Number,
@@ -607,6 +608,12 @@ export class CollectionSchemaView extends CollectionSubView() {
         this.closeColumnMenu();
     };
 
+    setColumnValues = (key: string, value: string) => {
+        let success: boolean = true;
+        this.childDocs.forEach(doc => success && KeyValueBox.SetField(doc, key, value));
+        return success;
+    };
+
     @action
     openColumnMenu = (index: number, newCol: boolean) => {
         this._makeNewColumn = false;
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 05197d05f..37999484d 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -120,7 +120,14 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 </div>
                 <div className="row-cells">
                     {this.schemaView?.columnKeys?.map((key, index) => (
-                        <SchemaTableCell key={key} Document={this.rootDoc} fieldKey={key} columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth} isRowActive={this.props.isContentActive} />
+                        <SchemaTableCell
+                            key={key}
+                            Document={this.rootDoc}
+                            fieldKey={key}
+                            columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
+                            isRowActive={this.props.isContentActive}
+                            setColumnValues={(field, value) => this.schemaView?.setColumnValues(field, value) ?? false}
+                        />
                     ))}
                 </div>
             </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index d475c3b6f..13e45963e 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -15,6 +15,7 @@ export interface SchemaTableCellProps {
     fieldKey: string;
     columnWidth: number;
     isRowActive: () => boolean | undefined;
+    setColumnValues: (field: string, value: string) => boolean;
 }
 
 @observer
@@ -53,7 +54,12 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
                     <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)}
+                        SetValue={(value: string, shiftDown?: boolean, enterKey?: boolean) => {
+                            if (shiftDown && enterKey) {
+                                this.props.setColumnValues(this.props.fieldKey, value);
+                            }
+                            return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
+                        }}
                         editing={this.props.isRowActive() ? undefined : false}
                     />
                 </div>
-- 
cgit v1.2.3-70-g09d2


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

---
 src/client/documents/Documents.ts                  | 51 ++++++++++++----------
 .../collectionSchema/CollectionSchemaView.scss     | 11 ++++-
 .../collectionSchema/CollectionSchemaView.tsx      | 48 +++++++++++++++-----
 .../collections/collectionSchema/SchemaRowBox.tsx  |  1 +
 .../collectionSchema/SchemaTableCell.tsx           |  8 +++-
 5 files changed, 82 insertions(+), 37 deletions(-)

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

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


From 5cd64622f14ede408d3baca4a10d155b60392e46 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 13 Apr 2023 22:22:07 -0400
Subject: lots of changes to get rid of ContainingCollectionDoc and
 ContainingCollectionView props.

---
 src/client/documents/Documents.ts                  |  8 +--
 src/client/util/CurrentUserUtils.ts                |  2 +-
 src/client/util/DocumentManager.ts                 | 83 ++++++++++------------
 src/client/util/DragManager.ts                     |  4 +-
 .../util/Import & Export/DirectoryImportBox.tsx    |  6 +-
 src/client/util/ReplayMovements.ts                 | 64 ++++++-----------
 src/client/util/SelectionManager.ts                |  6 +-
 src/client/util/SharingManager.tsx                 |  5 +-
 src/client/util/TrackMovements.ts                  | 36 +++++-----
 src/client/views/DashboardView.tsx                 | 17 ++---
 src/client/views/DocComponent.tsx                  |  1 -
 src/client/views/DocumentDecorations.tsx           |  8 +--
 src/client/views/GestureOverlay.tsx                |  4 +-
 src/client/views/InkStrokeProperties.ts            |  3 +-
 src/client/views/LightboxView.tsx                  |  4 +-
 src/client/views/MainView.tsx                      | 20 ++----
 src/client/views/OverlayView.tsx                   | 10 +--
 src/client/views/Palette.tsx                       | 31 ++++----
 src/client/views/PropertiesDocContextSelector.tsx  | 22 ++++--
 src/client/views/PropertiesView.tsx                |  2 -
 src/client/views/StyleProvider.tsx                 | 11 ++-
 src/client/views/TemplateMenu.tsx                  |  2 -
 .../views/collections/CollectionCarouselView.tsx   |  1 -
 src/client/views/collections/CollectionMenu.tsx    |  6 +-
 .../views/collections/CollectionNoteTakingView.tsx |  4 --
 .../views/collections/CollectionPileView.tsx       |  2 +-
 .../collections/CollectionStackedTimeline.tsx      |  2 -
 .../views/collections/CollectionStackingView.tsx   |  4 --
 .../views/collections/CollectionTreeView.tsx       | 10 +--
 src/client/views/collections/CollectionView.tsx    |  5 +-
 src/client/views/collections/TabDocView.tsx        |  6 +-
 src/client/views/collections/TreeView.tsx          | 54 ++++++--------
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 31 ++++----
 .../collectionLinear/CollectionLinearView.tsx      |  5 +-
 .../CollectionMulticolumnView.tsx                  |  2 -
 .../CollectionMultirowView.tsx                     |  2 -
 .../collectionSchema/CollectionSchemaView.tsx      |  6 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  |  2 +-
 .../collectionSchema/SchemaTableCell.tsx           |  2 -
 src/client/views/linking/LinkMenuItem.tsx          | 21 +-----
 src/client/views/linking/LinkPopup.tsx             |  4 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  7 +-
 src/client/views/nodes/DocumentContentsView.tsx    |  1 -
 src/client/views/nodes/DocumentLinksButton.tsx     |  2 +-
 src/client/views/nodes/DocumentView.tsx            | 12 ++--
 src/client/views/nodes/FieldView.tsx               |  1 +
 src/client/views/nodes/KeyValuePair.tsx            |  2 -
 src/client/views/nodes/LinkDocPreview.tsx          |  4 +-
 src/client/views/nodes/ScreenshotBox.tsx           |  5 +-
 src/client/views/nodes/button/FontIconBox.tsx      |  4 +-
 .../views/nodes/formattedText/DashDocView.tsx      |  7 +-
 .../views/nodes/formattedText/DashFieldView.tsx    |  5 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx | 20 ++++--
 src/client/views/nodes/trails/PresBox.tsx          |  1 -
 src/client/views/nodes/trails/PresElementBox.tsx   | 27 ++++---
 src/client/views/topbar/TopBar.tsx                 | 51 ++-----------
 src/mobile/AudioUpload.tsx                         | 76 ++++++++++----------
 src/mobile/MobileInterface.tsx                     |  4 +-
 58 files changed, 291 insertions(+), 456 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 8d97ce5af..09b45a481 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1285,10 +1285,6 @@ export namespace DocUtils {
         return rangeFilteredDocs;
     }
 
-    export function DefaultFocus(doc: Doc, options: DocFocusOptions) {
-        return undefined;
-    }
-
     export let ActiveRecordings: { props: FieldViewProps; getAnchor: (addAsAnnotation: boolean) => Doc }[] = [];
 
     export function MakeLinkToActiveAudio(getSourceDoc: () => Doc | undefined, broadcastEvent = true) {
@@ -1299,10 +1295,9 @@ export namespace DocUtils {
         });
     }
 
-    export function MakeLink(source: Doc, target: Doc, linkSettings: { linkRelationship?: string; description?: string; linkDisplay?: boolean }, id?: string, allowParCollectionLink?: boolean, showPopup?: number[]) {
+    export function MakeLink(source: Doc, target: Doc, linkSettings: { linkRelationship?: string; description?: string; linkDisplay?: boolean }, id?: string, showPopup?: number[]) {
         if (!linkSettings.linkRelationship) linkSettings.linkRelationship = target.type === DocumentType.RTF ? 'Commentary:Comments On' : 'link';
         const sv = DocumentManager.Instance.getDocumentView(source);
-        if (!allowParCollectionLink && sv?.props.ContainingCollectionDoc === target) return;
         if (target.doc === Doc.UserDoc()) return undefined;
 
         const makeLink = action((linkDoc: Doc, showPopup?: number[]) => {
@@ -1371,7 +1366,6 @@ export namespace DocUtils {
                         value: 'any',
                         _readOnly_: 'boolean',
                         scriptContext: 'any',
-                        thisContainer: Doc.name,
                         documentView: Doc.name,
                         heading: Doc.name,
                         checked: 'boolean',
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 76ea3e3ea..abf7313a4 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -110,7 +110,7 @@ export class CurrentUserUtils {
         const tempClicks = DocCast(doc[field]);
         const reqdClickOpts:DocumentOptions = {_width: 300, _height:200, system: true};
         const reqdTempOpts:{opts:DocumentOptions, script: string}[] = [
-            { opts: { title: "Open In Target",        targetScriptKey: "onChildClick"},       script: "docCast(thisContainer.target).then((target) => target && (target.proto.data = new List([self])))"},
+            { opts: { title: "Open In Target",        targetScriptKey: "onChildClick"},       script: "docCast(documentView?.props.docViewPath().lastElement()?.rootDoc.target).then((target) => target && (target.proto.data = new List([self])))"},
             { opts: { title: "Open Detail On Right",  targetScriptKey: "onChildDoubleClick"}, script: `openDoc(self.doubleClickView.${OpenWhere.addRight})`}];
         const reqdClickList = reqdTempOpts.map(opts => {
             const allOpts = {...reqdClickOpts, ...opts.opts};
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index ccf370662..ad89e8653 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -1,15 +1,11 @@
-import { loadAsync } from 'jszip';
-import { action, observable, ObservableSet, runInAction } from 'mobx';
+import { action, observable, ObservableSet } from 'mobx';
 import { AnimationSym, Doc, Opt } from '../../fields/Doc';
 import { Id } from '../../fields/FieldSymbols';
 import { listSpec } from '../../fields/Schema';
 import { Cast, DocCast, StrCast } from '../../fields/Types';
 import { AudioField } from '../../fields/URLField';
-import { emptyFunction } from '../../Utils';
 import { CollectionViewType } from '../documents/DocumentTypes';
 import { CollectionDockingView } from '../views/collections/CollectionDockingView';
-import { CollectionFreeFormView } from '../views/collections/collectionFreeForm';
-import { CollectionView } from '../views/collections/CollectionView';
 import { TabDocView } from '../views/collections/TabDocView';
 import { LightboxView } from '../views/LightboxView';
 import { MainView } from '../views/MainView';
@@ -39,7 +35,7 @@ export class DocumentManager {
     private _viewRenderedCbs: { doc: Doc; func: (dv: DocumentView) => any }[] = [];
     public AddViewRenderedCb = (doc: Opt<Doc>, func: (dv: DocumentView) => any) => {
         if (doc) {
-            const dv = this.getDocumentViewById(doc[Id]);
+            const dv = this.getDocumentView(doc);
             this._viewRenderedCbs.push({ doc, func });
             if (dv) {
                 this.callAddViewFuncs(dv);
@@ -129,42 +125,24 @@ export class DocumentManager {
         return this.getDocumentViewsById(doc[Id]);
     }
 
-    public getDocumentViewById(id: string, preferredCollection?: CollectionView): DocumentView | undefined {
-        if (!id) return undefined;
-        let toReturn: DocumentView | undefined;
-        const passes = preferredCollection ? [preferredCollection, undefined] : [undefined];
-
-        for (const pass of passes) {
-            Array.from(DocumentManager.Instance.DocumentViews).map(view => {
-                if (view.rootDoc[Id] === id && (!pass || view.props.ContainingCollectionView === preferredCollection)) {
-                    toReturn = view;
-                    return;
-                }
-            });
-            if (!toReturn) {
-                Array.from(DocumentManager.Instance.DocumentViews).map(view => {
-                    const doc = view.rootDoc.proto;
-                    if (doc && doc[Id] === id && (!pass || view.props.ContainingCollectionView === preferredCollection)) {
-                        toReturn = view;
-                    }
-                });
-            } else {
-                break;
-            }
-        }
-
-        return toReturn;
-    }
-
-    public getDocumentView(toFind: Doc, preferredCollection?: CollectionView): DocumentView | undefined {
-        const found =
+    public getDocumentView(toFind: Doc | undefined, preferredCollection?: DocumentView): DocumentView | undefined {
+        const doc =
+            // bcz: this was temporary code used to match documents by data url instead of by id. intended only for repairing the DB
             // Array.from(DocumentManager.Instance.DocumentViews).find(
             //     dv =>
             //         ((dv.rootDoc.data as any)?.url?.href && (dv.rootDoc.data as any)?.url?.href === (toFind.data as any)?.url?.href) ||
             //         ((DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href && (DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href === (DocCast(toFind.annotationOn)?.data as any)?.url?.href)
             // )?.rootDoc ??
             toFind;
-        return this.getDocumentViewById(found[Id], preferredCollection);
+        const docViewArray = Array.from(DocumentManager.Instance.DocumentViews);
+        const passes = !doc ? [] : preferredCollection ? [preferredCollection, undefined] : [undefined];
+        return passes.reduce(
+            (pass, toReturn) =>
+                toReturn ??
+                docViewArray.filter(view => view.rootDoc === doc).find(view => !pass || view.props.docViewPath().lastElement() === preferredCollection) ??
+                docViewArray.filter(view => Doc.GetProto(view.rootDoc) === doc).find(view => !pass || view.props.docViewPath().lastElement() === preferredCollection),
+            undefined as Opt<DocumentView>
+        );
     }
 
     public getLightboxDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => {
@@ -247,7 +225,8 @@ export class DocumentManager {
     public showDocumentView = async (targetDocView: DocumentView, options: DocFocusOptions) => {
         const docViewPath = targetDocView.docViewPath.slice();
         let rootContextView = docViewPath.shift();
-        return rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined }));
+        await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined })));
+        if (options.toggleTarget && (!options.didMove || targetDocView.rootDoc.hidden)) targetDocView.rootDoc.hidden = !targetDocView.rootDoc.hidden;
     };
 
     // shows a document by first:
@@ -318,15 +297,25 @@ export class DocumentManager {
         }
     }
 }
-export function DocFocusOrOpen(doc: Doc, collectionDoc?: Doc) {
-    const cv = collectionDoc && DocumentManager.Instance.getDocumentView(collectionDoc);
-    const dv = DocumentManager.Instance.getDocumentView(doc, (cv?.ComponentView as CollectionFreeFormView)?.props.CollectionView);
-    if (dv) {
-        DocumentManager.Instance.showDocumentView(dv, { willZoomCentered: true });
-    } else {
-        const context = doc.context !== Doc.MyFilesystem && Cast(doc.context, Doc, null);
-        const showDoc = context || doc;
-        DocumentManager.Instance.showDocument(Doc.BestAlias(showDoc), { openLocation: OpenWhere.addRight }, () => DocumentManager.Instance.showDocument(doc, { willZoomCentered: true }));
-    }
+export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCentered: true, openLocation: OpenWhere.addRight }, containingDoc?: Doc) {
+    const func = () => {
+        const cv = DocumentManager.Instance.getDocumentView(containingDoc);
+        const dv = DocumentManager.Instance.getDocumentView(doc, cv);
+        if (dv && (!containingDoc || dv.props.docViewPath().lastElement()?.Document === containingDoc)) {
+            DocumentManager.Instance.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.rootDoc));
+        } else {
+            const showDoc = Doc.BestAlias(DocCast((containingDoc ?? doc.context) !== Doc.MyFilesystem ? containingDoc ?? doc.context : undefined, doc));
+            DocumentManager.Instance.showDocument(showDoc, { ...options, toggleTarget: undefined }, () => DocumentManager.Instance.showDocument(doc, options)).then(() => {
+                const cv = DocumentManager.Instance.getDocumentView(containingDoc);
+                const dv = DocumentManager.Instance.getDocumentView(doc, cv);
+                dv && Doc.linkFollowHighlight(dv.rootDoc);
+            });
+        }
+    };
+    if (doc.hidden) {
+        doc.hidden = false;
+        options.toggleTarget = false;
+        setTimeout(func);
+    } else func();
 }
 ScriptingGlobals.add(DocFocusOrOpen);
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 7d2aa813f..7e6de5e67 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -3,10 +3,8 @@ import { DateField } from '../../fields/DateField';
 import { Doc, Field, Opt, StrListCast } from '../../fields/Doc';
 import { List } from '../../fields/List';
 import { PrefetchProxy } from '../../fields/Proxy';
-import { listSpec } from '../../fields/Schema';
-import { SchemaHeaderField } from '../../fields/SchemaHeaderField';
 import { ScriptField } from '../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../fields/Types';
+import { BoolCast, ScriptCast, StrCast } from '../../fields/Types';
 import { emptyFunction, Utils } from '../../Utils';
 import { Docs, DocUtils } from '../documents/Documents';
 import * as globalCssVariables from '../views/global/globalCssVariables.scss';
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx
index 559958c2b..76b1323c4 100644
--- a/src/client/util/Import & Export/DirectoryImportBox.tsx	
+++ b/src/client/util/Import & Export/DirectoryImportBox.tsx	
@@ -14,12 +14,14 @@ import { AcceptableMedia, Upload } from '../../../server/SharedMediaTypes';
 import { Utils } from '../../../Utils';
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { Docs, DocumentOptions, DocUtils } from '../../documents/Documents';
+import { DocumentType } from '../../documents/DocumentTypes';
 import { Networking } from '../../Network';
 import { FieldView, FieldViewProps } from '../../views/nodes/FieldView';
 import { DocumentManager } from '../DocumentManager';
 import './DirectoryImportBox.scss';
 import ImportMetadataEntry, { keyPlaceholder, valuePlaceholder } from './ImportMetadataEntry';
 import React = require('react');
+import _ = require('lodash');
 
 const unsupported = ['text/html', 'text/plain'];
 
@@ -155,8 +157,8 @@ export class DirectoryImportBox extends React.Component<FieldViewProps> {
             x: NumCast(doc.x),
             y: NumCast(doc.y) + offset,
         };
-        const parent = this.props.ContainingCollectionView;
-        if (parent) {
+        const parent = _.nth(this.props.docViewPath(), -2); // last element of path is this box's document view, 2nd to last is any collection or other document that may contain it.
+        if (parent?.rootDoc.type === DocumentType.COL) {
             let importContainer: Doc;
             if (docs.length < 50) {
                 importContainer = Docs.Create.MasonryDocument(docs, options);
diff --git a/src/client/util/ReplayMovements.ts b/src/client/util/ReplayMovements.ts
index d5bffc5e2..40261985a 100644
--- a/src/client/util/ReplayMovements.ts
+++ b/src/client/util/ReplayMovements.ts
@@ -7,6 +7,7 @@ import { CollectionDockingView } from '../views/collections/CollectionDockingVie
 import { DocServer } from '../DocServer';
 import { Movement, Presentation } from './TrackMovements';
 import { OpenWhereMod } from '../views/nodes/DocumentView';
+import { returnTransparent } from '../../Utils';
 
 export class ReplayMovements {
     private timers: NodeJS.Timeout[] | null;
@@ -60,17 +61,11 @@ export class ReplayMovements {
             return;
         }
 
-        let docIdtoDoc: Map<string, Doc> = new Map();
-        try {
-            docIdtoDoc = await this.loadPresentation(presentation);
-        } catch {
-            console.error('[recordingApi.ts] setVideoBox(): error loading presentation - no replay movements');
-            throw 'error loading docs from server';
-        }
+        const docIdtoDoc = this.loadPresentation(presentation);
 
         this.videoBoxDisposeFunc = reaction(
             () => ({ playing: videoBox._playing, timeViewed: videoBox.player?.currentTime || 0 }),
-            ({ playing, timeViewed }) => (playing ? this.playMovements(presentation, docIdtoDoc, timeViewed) : this.pauseMovements())
+            ({ playing, timeViewed }) => (playing ? this.playMovements(presentation, timeViewed) : this.pauseMovements())
         );
         this.videoBox = videoBox;
     };
@@ -93,45 +88,33 @@ export class ReplayMovements {
         this.pauseMovements();
     };
 
-    loadPresentation = async (presentation: Presentation) => {
+    loadPresentation = (presentation: Presentation) => {
         const { movements } = presentation;
         if (movements === null) {
             throw '[recordingApi.ts] followMovements() failed: no presentation data';
         }
 
         // generate a set of all unique docIds
-        const docIds = new Set<string>();
-        for (const { docId } of movements) {
-            if (!docIds.has(docId)) docIds.add(docId);
-        }
-
-        const docIdtoDoc = new Map<string, Doc>();
-
-        let refFields = await DocServer.GetRefFields([...docIds.keys()]);
-        for (const docId in refFields) {
-            if (!refFields[docId]) {
-                throw `one field was undefined`;
-            }
-            docIdtoDoc.set(docId, refFields[docId] as Doc);
+        const docs = new Set<Doc>();
+        for (const { doc } of movements) {
+            if (!docs.has(doc)) docs.add(doc);
         }
-        // console.info('loadPresentation refFields', refFields, docIdtoDoc);
 
-        return docIdtoDoc;
+        return docs;
     };
 
     // returns undefined if the docView isn't open on the screen
-    getCollectionFFView = (docId: string) => {
-        const isInView = DocumentManager.Instance.getDocumentViewById(docId);
+    getCollectionFFView = (doc: Doc) => {
+        const isInView = DocumentManager.Instance.getDocumentView(doc);
         if (isInView) {
             return isInView.ComponentView as CollectionFreeFormView;
         }
     };
 
     // will open the doc in a tab then return the CollectionFFView that holds it
-    openTab = (docId: string, docIdtoDoc: Map<string, Doc>) => {
-        const doc = docIdtoDoc.get(docId);
-        if (doc == undefined) {
-            console.error(`docIdtoDoc did not contain docId ${docId}`);
+    openTab = (doc: Doc) => {
+        if (doc === undefined) {
+            console.error(`doc undefined`);
             return undefined;
         }
         // console.log('openTab', docId, doc);
@@ -149,13 +132,12 @@ export class ReplayMovements {
         document.Document._panY = panY;
     };
 
-    getFirstMovements = (movements: Movement[]): Map<string, Movement> => {
+    getFirstMovements = (movements: Movement[]): Map<Doc, Movement> => {
         if (movements === null) return new Map();
         // generate a set of all unique docIds
-        const docIdtoFirstMove = new Map();
+        const docIdtoFirstMove = new Map<Doc, Movement>();
         for (const move of movements) {
-            const { docId } = move;
-            if (!docIdtoFirstMove.has(docId)) docIdtoFirstMove.set(docId, move);
+            if (!docIdtoFirstMove.has(move.doc)) docIdtoFirstMove.set(move.doc, move);
         }
         return docIdtoFirstMove;
     };
@@ -165,7 +147,7 @@ export class ReplayMovements {
         Doc.UserDoc().presentationMode = 'none';
     };
 
-    public playMovements = (presentation: Presentation, docIdtoDoc: Map<string, Doc>, timeViewed: number = 0) => {
+    public playMovements = (presentation: Presentation, timeViewed: number = 0) => {
         // console.info('playMovements', presentation, timeViewed, docIdtoDoc);
 
         if (presentation.movements === null || presentation.movements.length === 0) {
@@ -183,13 +165,13 @@ export class ReplayMovements {
         const handleFirstMovements = () => {
             // if the first movement is a closed tab, open it
             const firstMovement = filteredMovements[0];
-            const isClosed = this.getCollectionFFView(firstMovement.docId) === undefined;
-            if (isClosed) this.openTab(firstMovement.docId, docIdtoDoc);
+            const isClosed = this.getCollectionFFView(firstMovement.doc) === undefined;
+            if (isClosed) this.openTab(firstMovement.doc);
 
             // for the open tabs, set it to the first move
             const docIdtoFirstMove = this.getFirstMovements(filteredMovements);
-            for (const [docId, firstMove] of docIdtoFirstMove) {
-                const colFFView = this.getCollectionFFView(docId);
+            for (const [doc, firstMove] of docIdtoFirstMove) {
+                const colFFView = this.getCollectionFFView(doc);
                 if (colFFView) this.zoomAndPan(firstMove, colFFView);
             }
         };
@@ -200,12 +182,12 @@ export class ReplayMovements {
             const timeDiff = movement.time - timeViewed * 1000;
 
             return setTimeout(() => {
-                const collectionFFView = this.getCollectionFFView(movement.docId);
+                const collectionFFView = this.getCollectionFFView(movement.doc);
                 if (collectionFFView) {
                     this.zoomAndPan(movement, collectionFFView);
                 } else {
                     // tab wasn't open - open it and play the movement
-                    const openedColFFView = this.openTab(movement.docId, docIdtoDoc);
+                    const openedColFFView = this.openTab(movement.doc);
                     console.log('openedColFFView', openedColFFView);
                     openedColFFView && this.zoomAndPan(movement, openedColFFView);
                 }
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 313c255a0..bfad93334 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -1,4 +1,3 @@
-import { ModalManager } from '@material-ui/core';
 import { action, observable, ObservableMap } from 'mobx';
 import { computedFn } from 'mobx-utils';
 import { Doc, Opt } from '../../fields/Doc';
@@ -64,8 +63,9 @@ export namespace SelectionManager {
     export function DeselectView(docView?: DocumentView): void {
         manager.DeselectView(docView);
     }
-    export function SelectView(docView: DocumentView, ctrlPressed: boolean): void {
-        manager.SelectView(docView, ctrlPressed);
+    export function SelectView(docView: DocumentView | undefined, ctrlPressed: boolean): void {
+        if (!docView) DeselectAll();
+        else manager.SelectView(docView, ctrlPressed);
     }
     export function SelectSchemaViewDoc(document: Opt<Doc>, deselectAllFirst?: boolean): void {
         if (deselectAllFirst) manager.DeselectAll();
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 3c05af4bb..a73eda04c 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -370,11 +370,10 @@ export class SharingManager extends React.Component<{}> {
         const docs = SelectionManager.Views().length > 1 ? SelectionManager.Views().map(docView => docView.props.Document) : [this.targetDoc];
         return (
             <span
-                className={'focus-span'}
+                className="focus-span"
                 title={title}
                 onClick={() => {
-                    let context: Opt<CollectionView>;
-                    if (this.targetDoc && this.targetDocView && docs.length === 1 && (context = this.targetDocView.props.ContainingCollectionView)) {
+                    if (this.targetDoc && this.targetDocView && docs.length === 1) {
                         DocumentManager.Instance.showDocument(this.targetDoc, { willZoomCentered: true });
                     }
                 }}
diff --git a/src/client/util/TrackMovements.ts b/src/client/util/TrackMovements.ts
index 4a2ccd706..2f16307b3 100644
--- a/src/client/util/TrackMovements.ts
+++ b/src/client/util/TrackMovements.ts
@@ -9,7 +9,7 @@ export type Movement = {
     panX: number;
     panY: number;
     scale: number;
-    docId: string;
+    doc: Doc;
 };
 
 export type Presentation = {
@@ -28,7 +28,7 @@ export class TrackMovements {
     private tracking: boolean;
     private absoluteStart: number;
     // instance variable for holding the FFViews and their disposers
-    private recordingFFViews: Map<string, IReactionDisposer> | null;
+    private recordingFFViews: Map<Doc, IReactionDisposer> | null;
     private tabChangeDisposeFunc: IReactionDisposer | null;
 
     // create static instance and getter for global use
@@ -55,33 +55,33 @@ export class TrackMovements {
         return this.currentPresentation.movements === null;
     }
 
-    private addRecordingFFView(doc: Doc, key: string = doc[Id]): void {
+    private addRecordingFFView(doc: Doc): void {
         // console.info('adding dispose func : docId', key, 'doc', doc);
 
         if (this.recordingFFViews === null) {
             console.warn('addFFView on null RecordingApi');
             return;
         }
-        if (this.recordingFFViews.has(key)) {
-            console.warn('addFFView : key already in map');
+        if (this.recordingFFViews.has(doc)) {
+            console.warn('addFFView : doc already in map');
             return;
         }
 
         const disposeFunc = reaction(
             () => ({ x: NumCast(doc.panX, -1), y: NumCast(doc.panY, -1), scale: NumCast(doc.viewScale, 0) }),
-            res => res.x !== -1 && res.y !== -1 && this.tracking && this.trackMovement(res.x, res.y, key, res.scale)
+            res => res.x !== -1 && res.y !== -1 && this.tracking && this.trackMovement(res.x, res.y, doc, res.scale)
         );
-        this.recordingFFViews?.set(key, disposeFunc);
+        this.recordingFFViews?.set(doc, disposeFunc);
     }
 
-    private removeRecordingFFView = (key: string) => {
+    private removeRecordingFFView = (doc: Doc) => {
         // console.info('removing dispose func : docId', key);
         if (this.recordingFFViews === null) {
             console.warn('removeFFView on null RecordingApi');
             return;
         }
-        this.recordingFFViews.get(key)?.();
-        this.recordingFFViews.delete(key);
+        this.recordingFFViews.get(doc)?.();
+        this.recordingFFViews.delete(doc);
     };
 
     // in the case where only one tab was changed (updates not across dashboards), set only one to true
@@ -90,15 +90,15 @@ export class TrackMovements {
 
         // so that the size comparisons are correct, we must filter to only the FFViews
         const isFFView = (doc: Doc) => doc && 'viewType' in doc && doc.viewType === 'freeform';
-        const tabbedFFViews = new Set<string>();
+        const tabbedFFViews = new Set<Doc>();
         for (const DashDoc of tabbedDocs) {
-            if (isFFView(DashDoc)) tabbedFFViews.add(DashDoc[Id]);
+            if (isFFView(DashDoc)) tabbedFFViews.add(DashDoc);
         }
 
         // new tab was added - need to add it
         if (tabbedFFViews.size > this.recordingFFViews.size) {
             for (const DashDoc of tabbedDocs) {
-                if (!this.recordingFFViews.has(DashDoc[Id])) {
+                if (!this.recordingFFViews.has(DashDoc)) {
                     if (isFFView(DashDoc)) {
                         this.addRecordingFFView(DashDoc);
 
@@ -110,9 +110,9 @@ export class TrackMovements {
         }
         // tab was removed - need to remove it from recordingFFViews
         else if (tabbedFFViews.size < this.recordingFFViews.size) {
-            for (const [key] of this.recordingFFViews) {
-                if (!tabbedFFViews.has(key)) {
-                    this.removeRecordingFFView(key);
+            for (const [doc] of this.recordingFFViews) {
+                if (!tabbedFFViews.has(doc)) {
+                    this.removeRecordingFFView(doc);
                     if (onlyOne) return;
                 }
             }
@@ -214,7 +214,7 @@ export class TrackMovements {
         }
     };
 
-    private trackMovement = (panX: number, panY: number, docId: string, scale: number = 0) => {
+    private trackMovement = (panX: number, panY: number, doc: Doc, scale: number = 0) => {
         // ensure we are recording to track
         if (!this.tracking) {
             console.error('[recordingApi.ts] trackMovements(): tracking is false');
@@ -231,7 +231,7 @@ export class TrackMovements {
         // get the time
         const time = new Date().getTime() - this.absoluteStart;
         // make new movement object
-        const movement: Movement = { time, panX, panY, scale, docId };
+        const movement: Movement = { time, panX, panY, scale, doc };
 
         // add that movement to the current presentation data's movement array
         this.currentPresentation.movements && this.currentPresentation.movements.push(movement);
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 2b586b0e2..dee161931 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -109,17 +109,8 @@ export class DashboardView extends React.Component {
                     />
                 </div>
                 <div className="button-bar">
-                    <Button text="Cancel" borderRadius={10} hoverStyle={'gray'} fontSize={FontSize.SECONDARY} onClick={this.abortCreateNewDashboard} />
-                    <Button
-                        text="Create"
-                        borderRadius={10}
-                        backgroundColor={Colors.LIGHT_BLUE}
-                        hoverStyle={'darken'}
-                        fontSize={FontSize.SECONDARY}
-                        onClick={() => {
-                            this.createNewDashboard(this.newDashboardName!, this.newDashboardColor);
-                        }}
-                    />
+                    <Button text="Cancel" onClick={this.abortCreateNewDashboard} />
+                    <Button text="Create" onClick={() => this.createNewDashboard(this.newDashboardName!, this.newDashboardColor)} />
                 </div>
             </div>
         );
@@ -163,7 +154,7 @@ export class DashboardView extends React.Component {
                 <div className="dashboard-view">
                     <div className="left-menu">
                         <div className="new-dashboard-button">
-                            <Button icon={<FaPlus />} hoverStyle="darken" backgroundColor={Colors.LIGHT_BLUE} size={Size.MEDIUM} fontSize={FontSize.HEADER} text="New" onClick={() => this.setNewDashboardName('')} borderRadius={50} />
+                            <Button icon={<FaPlus />} size={Size.MEDIUM} text="New" onClick={() => this.setNewDashboardName('')} />
                         </div>
                         <div className={`text-button ${this.selectedDashboardGroup === DashboardGroup.MyDashboards && 'selected'}`} onClick={() => this.selectDashboardGroup(DashboardGroup.MyDashboards)}>
                             My Dashboards
@@ -196,7 +187,7 @@ export class DashboardView extends React.Component {
                                                 e.stopPropagation();
                                                 this.onContextMenu(dashboard, e);
                                             }}>
-                                            <IconButton isCircle={true} size={Size.SMALL} hoverStyle="gray" icon={<FontAwesomeIcon color="black" size="lg" icon="bars" />} />
+                                            <Button size={Size.SMALL} icon={<FontAwesomeIcon color="black" size="lg" icon="bars" />} />
                                         </div>
                                     </div>
                                 </div>
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 9fc1487a0..a59189fd2 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -52,7 +52,6 @@ export function DocComponent<P extends DocComponentProps>() {
 interface ViewBoxBaseProps {
     Document: Doc;
     DataDoc?: Doc;
-    ContainingCollectionDoc: Opt<Doc>;
     DocumentView?: () => DocumentView;
     fieldKey: string;
     isSelected: (outsideReaction?: boolean) => boolean;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 9ffbe083f..9a4aaf00e 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -33,6 +33,7 @@ import { ImageBox } from './nodes/ImageBox';
 import React = require('react');
 import { RichTextField } from '../../fields/RichTextField';
 import { LinkFollower } from '../util/LinkFollower';
+import _ = require('lodash');
 
 @observer
 export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> {
@@ -303,8 +304,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         SelectionManager.DeselectAll();
     };
 
-    onSelectorClick = () => SelectionManager.Views()?.[0]?.props.ContainingCollectionView?.props.select(false);
-
+    onSelectorClick = () => SelectionManager.Views()?.[0]?.props.docViewPath?.().lastElement()?.select(false);
     /**
      * Handles setting up events when user clicks on the border radius editor
      * @param e PointerEvent
@@ -744,7 +744,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
             seldocview.props.hideDeleteButton ||
             seldocview.rootDoc.hideDeleteButton ||
             SelectionManager.Views().some(docView => {
-                const collectionAcl = docView.props.ContainingCollectionView ? GetEffectiveAcl(docView.props.ContainingCollectionDoc?.[DataSym]) : AclEdit;
+                const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DataSym]) : AclEdit;
                 return docView.rootDoc.stayInCollection || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin);
             });
 
@@ -865,7 +865,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                                     <div key="b" className={`documentDecorations-bottomResizer ${resizerScheme}`} onPointerDown={this.onPointerDown} onContextMenu={e => e.preventDefault()} />
                                     <div key="br" className={`documentDecorations-bottomRightResizer ${resizerScheme}`} onPointerDown={this.onPointerDown} onContextMenu={e => e.preventDefault()} />
 
-                                    {seldocview.props.renderDepth <= 1 || !seldocview.props.ContainingCollectionView ? null : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectorClick, 'tap to select containing document')}
+                                    {seldocview.props.renderDepth <= 1 || !seldocview.props.docViewPath().lastElement() ? null : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectorClick, 'tap to select containing document')}
                                 </>
                             )}
                             {useRounding && (
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 0feccb742..13faae783 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -1010,14 +1010,12 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
                 renderDepth={0}
                 styleProvider={returnEmptyString}
                 docViewPath={returnEmptyDoclist}
-                focus={DocUtils.DefaultFocus}
+                focus={emptyFunction}
                 whenChildContentsActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
                 docRangeFilters={returnEmptyFilter}
                 docFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
-                ContainingCollectionView={undefined}
-                ContainingCollectionDoc={undefined}
             />
         );
     };
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index e6df0801c..156825f41 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -373,10 +373,11 @@ export class InkStrokeProperties {
 
     snapToAllCurves = (screenDragPt: { X: number; Y: number }, inkView: DocumentView, snapData: { nearestPt: { X: number; Y: number }; distance: number }, ink: InkData, controlIndex: number) => {
         const containingCollection = inkView.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
+        const containingDocView = inkView.props.CollectionFreeFormDocumentView?.().props.DocumentView?.();
         containingCollection?.childDocs
             .filter(doc => doc.type === DocumentType.INK)
             .forEach(doc => {
-                const testInkView = DocumentManager.Instance.getDocumentView(doc, containingCollection?.props.CollectionView);
+                const testInkView = DocumentManager.Instance.getDocumentView(doc, containingDocView);
                 const snapped = testInkView?.ComponentView?.snapPt?.(screenDragPt, doc === inkView.rootDoc ? this.excludeSelfSnapSegs(ink, controlIndex) : []);
                 if (snapped && snapped.distance < snapData.distance) {
                     const snappedInkPt = doc === inkView.rootDoc ? snapped.nearestPt : inkView.ComponentView?.ptFromScreen?.(testInkView?.ComponentView?.ptToScreen?.(snapped.nearestPt) ?? { X: 0, Y: 0 }); // convert from snapped ink coordinate system to dragged ink coordinate system by converting to/from screen space
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index 976c8763e..69eec8456 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -266,8 +266,6 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                             docFilters={this.docFilters}
                             docRangeFilters={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
-                            ContainingCollectionView={undefined}
-                            ContainingCollectionDoc={undefined}
                             addDocument={undefined}
                             removeDocument={undefined}
                             whenChildContentsActiveChanged={emptyFunction}
@@ -275,7 +273,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                             pinToPres={TabDocView.PinDoc}
                             bringToFront={emptyFunction}
                             onBrowseClick={MainView.Instance.exploreMode}
-                            focus={DocUtils.DefaultFocus}
+                            focus={emptyFunction}
                         />
                     </GestureOverlay>
                 </div>
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 60459cf30..0384d925e 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -595,14 +595,12 @@ export class MainView extends React.Component {
                     PanelWidth={this.headerBarDocWidth}
                     PanelHeight={this.headerBarDocHeight}
                     renderDepth={0}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                 />
             </div>
         );
@@ -626,14 +624,12 @@ export class MainView extends React.Component {
                     ScreenToLocalTransform={this._hideUI ? this.mainScreenToLocalXf : Transform.Identity}
                     PanelWidth={this.mainDocViewWidth}
                     PanelHeight={this.mainDocViewHeight}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     suppressSetHeight={true}
                     renderDepth={this._hideUI ? 0 : -1}
                 />
@@ -727,14 +723,12 @@ export class MainView extends React.Component {
                         renderDepth={0}
                         isContentActive={returnTrue}
                         scriptContext={CollectionDockingView.Instance?.props.Document}
-                        focus={DocUtils.DefaultFocus}
+                        focus={emptyFunction}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
                         docFilters={returnEmptyFilter}
                         docRangeFilters={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
                     />
                 </div>
                 {this.docButtons}
@@ -758,7 +752,7 @@ export class MainView extends React.Component {
                     PanelHeight={this.leftMenuHeight}
                     renderDepth={0}
                     docViewPath={returnEmptyDoclist}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     styleProvider={DefaultStyleProvider}
                     isContentActive={returnTrue}
                     whenChildContentsActiveChanged={emptyFunction}
@@ -766,8 +760,6 @@ export class MainView extends React.Component {
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     scriptContext={this}
                 />
             </div>
@@ -900,13 +892,11 @@ export class MainView extends React.Component {
                     PanelWidth={this.leftMenuFlyoutWidth}
                     PanelHeight={this.leftMenuFlyoutHeight}
                     renderDepth={0}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                 />
                 {['watching', 'recording'].includes(String(this.userDoc?.presentationMode) ?? '') ? <div style={{ border: '.5rem solid green', padding: '5px' }}>{StrCast(this.userDoc?.presentationMode)}</div> : <></>}
             </div>
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index ec22128d4..bdc48d03a 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -1,4 +1,4 @@
-import { action, computed, observable, trace } from 'mobx';
+import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import * as React from 'react';
@@ -10,15 +10,13 @@ import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, retu
 import { DocUtils } from '../documents/Documents';
 import { DocumentType } from '../documents/DocumentTypes';
 import { DragManager } from '../util/DragManager';
-import { ScriptingGlobals } from '../util/ScriptingGlobals';
 import { Transform } from '../util/Transform';
 import { CollectionFreeFormLinksView } from './collections/collectionFreeForm/CollectionFreeFormLinksView';
 import { LightboxView } from './LightboxView';
 import { MainView } from './MainView';
 import { DocumentView } from './nodes/DocumentView';
 import './OverlayView.scss';
-import { ScriptingRepl } from './ScriptingRepl';
-import { DefaultStyleProvider, testDocProps } from './StyleProvider';
+import { DefaultStyleProvider } from './StyleProvider';
 
 export type OverlayDisposer = () => void;
 
@@ -223,7 +221,7 @@ export class OverlayView extends React.Component {
                             isDocumentActive={returnTrue}
                             isContentActive={returnTrue}
                             whenChildContentsActiveChanged={emptyFunction}
-                            focus={DocUtils.DefaultFocus}
+                            focus={emptyFunction}
                             styleProvider={DefaultStyleProvider}
                             docViewPath={returnEmptyDoclist}
                             addDocTab={d.type === DocumentType.PRES ? MainView.addDocTabFunc : returnFalse}
@@ -231,8 +229,6 @@ export class OverlayView extends React.Component {
                             docFilters={returnEmptyFilter}
                             docRangeFilters={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
-                            ContainingCollectionView={undefined}
-                            ContainingCollectionDoc={undefined}
                         />
                     </div>
                 );
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 954529bc9..3ad28c418 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -1,12 +1,12 @@
-import { IReactionDisposer, observable, reaction } from "mobx";
-import { observer } from "mobx-react";
-import * as React from "react";
-import { Doc } from "../../fields/Doc";
-import { NumCast } from "../../fields/Types";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, emptyPath } from "../../Utils";
-import { Transform } from "../util/Transform";
-import { DocumentView } from "./nodes/DocumentView";
-import "./Palette.scss";
+import { IReactionDisposer, observable, reaction } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Doc } from '../../fields/Doc';
+import { NumCast } from '../../fields/Types';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, emptyPath } from '../../Utils';
+import { Transform } from '../util/Transform';
+import { DocumentView } from './nodes/DocumentView';
+import './Palette.scss';
 
 export interface PaletteProps {
     x: number;
@@ -23,20 +23,20 @@ export default class Palette extends React.Component<PaletteProps> {
     componentDidMount = () => {
         this._selectedDisposer = reaction(
             () => NumCast(this.props.thumbDoc.selectedIndex),
-            (i) => this._selectedIndex = i,
+            i => (this._selectedIndex = i),
             { fireImmediately: true }
         );
-    }
+    };
 
     componentWillUnmount = () => {
         this._selectedDisposer?.();
-    }
+    };
 
     render() {
         return (
             <div className="palette-container" style={{ transform: `translate(${this.props.x}px, ${this.props.y}px)` }}>
                 <div className="palette-thumb" style={{ transform: `translate(${this.props.thumb[0] - this.props.x}px, ${this.props.thumb[1] - this.props.y}px)` }}>
-                    <div className="palette-thumbContent" style={{ transform: `translate(-${(this._selectedIndex * 50) + 10}px, 0px)` }}>
+                    <div className="palette-thumbContent" style={{ transform: `translate(-${this._selectedIndex * 50 + 10}px, 0px)` }}>
                         <DocumentView
                             Document={this.props.thumbDoc}
                             DataDoc={undefined}
@@ -59,12 +59,11 @@ export default class Palette extends React.Component<PaletteProps> {
                             docFilters={returnEmptyFilter}
                             docRangeFilters={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
-                            ContainingCollectionView={undefined}
-                            ContainingCollectionDoc={undefined} />
+                        />
                         <div className="palette-cover" style={{ transform: `translate(${Math.max(0, this._selectedIndex) * 50.75 + 23}px, 0px)` }}></div>
                     </div>
                 </div>
             </div>
         );
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index 2c7da5931..93eec61f3 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -22,9 +22,9 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
     @computed get _docs() {
         if (!this.props.DocView) return [];
         const target = this.props.DocView.props.Document;
-        const targetContext = this.props.DocView.props.ContainingCollectionDoc;
+        const targetContext = this.props.DocView.props.docViewPath().lastElement()?.rootDoc;
         const aliases = DocListCast(target.aliases);
-        const containerProtos = aliases.filter(alias => alias.context && alias.context instanceof Doc && Cast(alias.context, Doc, null) !== targetContext).reduce((set, alias) => set.add(Cast(alias.context, Doc, null)), new Set<Doc>());
+        const containerProtos = aliases.filter(alias => alias.context && alias.context instanceof Doc).reduce((set, alias) => set.add(Cast(alias.context, Doc, null)), new Set<Doc>());
         const containerSets = Array.from(containerProtos.keys()).map(container => DocListCast(container.aliases));
         const containers = containerSets.reduce((p, set) => {
             set.map(s => p.add(s));
@@ -42,6 +42,7 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
         return doclayouts
             .filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance?.props.Document))
             .filter(doc => !Doc.IsSystem(doc))
+            .filter(doc => doc !== targetContext)
             .map(doc => ({ col: doc, target }));
     }
 
@@ -53,8 +54,21 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
             col._panY = NumCast(target.y) + NumCast(target._height) / 2;
         }
         col.hidden = false;
-        this.props.addDocTab(col, (OpenWhere.toggle + ':' + OpenWhereMod.right) as OpenWhere);
-        setTimeout(() => DocFocusOrOpen(Doc.GetProto(this.props.DocView!.props.Document), col), 100);
+        //this.props.addDocTab(col, (OpenWhere.toggle + ':' + OpenWhereMod.right) as OpenWhere);
+        setTimeout(
+            () =>
+                this.props.DocView &&
+                DocFocusOrOpen(
+                    Doc.GetProto(this.props.DocView.props.Document),
+                    {
+                        //
+                        willZoomCentered: true,
+                        openLocation: (OpenWhere.toggle + ':' + OpenWhereMod.right) as OpenWhere,
+                    },
+                    col
+                ),
+            100
+        );
     };
 
     render() {
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index fbc7d7696..6582c3f2a 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -341,8 +341,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         docFilters={returnEmptyFilter}
                         docRangeFilters={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
-                        ContainingCollectionDoc={undefined}
-                        ContainingCollectionView={undefined}
                         addDocument={returnFalse}
                         moveDocument={undefined}
                         removeDocument={returnFalse}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index b950b4860..739d6d819 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -18,7 +18,7 @@ import { TreeSort } from './collections/TreeView';
 import { Colors } from './global/globalEnums';
 import { InkingStroke } from './InkingStroke';
 import { MainView } from './MainView';
-import { DocumentViewProps } from './nodes/DocumentView';
+import { DocumentViewProps, OpenWhere } from './nodes/DocumentView';
 import { FieldViewProps } from './nodes/FieldView';
 import { KeyValueBox } from './nodes/KeyValueBox';
 import { SliderBox } from './nodes/SliderBox';
@@ -295,7 +295,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 default:
                     return doc.z
                         ? `#9c9396  ${StrCast(doc?.boxShadow, '10px 10px 0.9vw')}` // if it's a floating doc, give it a big shadow
-                        : props?.ContainingCollectionDoc?._useClusters
+                        : props?.docViewPath().lastElement()?.rootDoc._useClusters
                         ? `${backgroundCol()} ${StrCast(doc.boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
                         : NumCast(doc.group, -1) !== -1
                         ? `gray ${StrCast(doc.boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
@@ -316,7 +316,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             return undefined; // fixes problem with tree view elements getting pointer events when the tree view is not active
         case StyleProp.Decorations:
             const lock = () => {
-                if (props?.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform) {
+                if (props?.docViewPath().lastElement()?.rootDoc?._viewType === CollectionViewType.Freeform) {
                     return doc?.pointerEvents !== 'none' ? null : (
                         <div className="styleProvider-lock" onClick={() => toggleLockedPosition(doc)}>
                             <FontAwesomeIcon icon={'lock'} style={{ color: 'red' }} size="lg" />
@@ -383,10 +383,7 @@ export function DashboardStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps
         return doc._viewType === CollectionViewType.Docking ? null : (
             <>
                 {DashboardToggleButton(doc, 'hidden', 'eye-slash', 'eye', () => {
-                    doc.hidden = doc.hidden ? undefined : true;
-                    if (!doc.hidden) {
-                        DocFocusOrOpen(doc, props?.ContainingCollectionDoc);
-                    }
+                    DocFocusOrOpen(doc, { toggleTarget: true, willPan: true, openLocation: OpenWhere.addRight }, props?.docViewPath().lastElement()?.rootDoc);
                 })}
             </>
         );
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 45db240a9..c5a501aa6 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -114,8 +114,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                 <CollectionTreeView
                     Document={Doc.MyTemplates}
                     CollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
-                    ContainingCollectionView={undefined}
                     styleProvider={DefaultStyleProvider}
                     setHeight={returnFalse}
                     docViewPath={returnEmptyDoclist}
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index c0220f804..0e4556eb4 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -62,7 +62,6 @@ export class CollectionCarouselView extends CollectionSubView() {
                         onClick={this.onContentClick}
                         hideCaptions={showCaptions ? true : false}
                         renderDepth={this.props.renderDepth + 1}
-                        ContainingCollectionView={this.props.CollectionView}
                         LayoutTemplate={this.props.childLayoutTemplate}
                         LayoutTemplateString={this.props.childLayoutString}
                         Document={curDoc.layout}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 225743748..2007f73aa 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -134,8 +134,6 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                 />
             </div>
         );
@@ -642,8 +640,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
                         key="float"
                         style={{
                             backgroundColor: this.props.docView.layoutDoc.z ? '121212' : undefined,
-                            pointerEvents: this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? 'none' : undefined,
-                            color: this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? 'dimgrey' : undefined,
+                            pointerEvents: this.props.docView.props.docViewPath().lastElement()?.rootDoc?._viewType !== CollectionViewType.Freeform ? 'none' : undefined,
+                            color: this.props.docView.props.docViewPath().lastElement()?.rootDoc?._viewType !== CollectionViewType.Freeform ? 'dimgrey' : undefined,
                         }}
                         onClick={undoBatch(() => this.props.docView.props.CollectionFreeFormDocumentView?.().float())}>
                         <FontAwesomeIcon icon={['fab', 'buffer']} size={'lg'} />
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index aec0734b4..80e81bc1c 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -255,8 +255,6 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                 hideTitle={this.props.childHideTitle?.()}
                 docRangeFilters={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
-                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                ContainingCollectionView={this.props.CollectionView}
                 addDocument={this.props.addDocument}
                 moveDocument={this.props.moveDocument}
                 removeDocument={this.props.removeDocument}
@@ -632,8 +630,6 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                         docFilters={this.props.docFilters}
                         docRangeFilters={this.props.docRangeFilters}
                         searchFilterDocs={this.props.searchFilterDocs}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
                     />
                 </div>
             );
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index ba90ed8cd..fd9b0c0ce 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -30,7 +30,7 @@ export class CollectionPileView extends CollectionSubView() {
         // pileups are designed to go away when they are empty.
         this._disposers.selected = reaction(
             () => this.childDocs.length,
-            num => !num && this.props.ContainingCollectionView?.removeDocument(this.props.Document)
+            num => !num && this.props.CollectionFreeFormDocumentView?.().props.removeDocument?.(this.props.Document)
         );
     }
     componentWillUnmount() {
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index bbd81d06d..22a575989 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -815,8 +815,6 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
                     whenChildContentsActiveChanged={emptyFunction}
                     focus={focusFunc}
                     isContentActive={returnFalse}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     searchFilterDocs={returnEmptyDoclist}
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index a85ee0e02..67f5dc9f4 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -346,8 +346,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 hideTitle={this.props.childHideTitle?.()}
                 docRangeFilters={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
-                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                ContainingCollectionView={this.props.CollectionView}
                 xPadding={NumCast(this.layoutDoc._childXPadding, this.props.childXPadding)}
                 yPadding={NumCast(this.layoutDoc._childYPadding, this.props.childYPadding)}
                 addDocument={this.props.addDocument}
@@ -678,8 +676,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                         docFilters={this.props.docFilters}
                         docRangeFilters={this.props.docRangeFilters}
                         searchFilterDocs={this.props.searchFilterDocs}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
                     />
                 </div>
             );
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 4a11e8f0b..92932fb61 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -164,7 +164,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
             this.props.removeDocument?.(doc);
             if (ind > 0) {
                 FormattedTextBox.SelectOnLoad = prev[Id];
-                DocumentManager.Instance.getDocumentView(prev, this.props.CollectionView)?.select(false);
+                DocumentManager.Instance.getDocumentView(prev, this.props.DocumentView?.())?.select(false);
             }
             return true;
         }
@@ -242,8 +242,6 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                 docFilters={returnEmptyFilter}
                 docRangeFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
-                ContainingCollectionDoc={this.doc}
-                ContainingCollectionView={this.props.CollectionView}
                 addDocument={returnFalse}
                 moveDocument={returnFalse}
                 removeDocument={returnFalse}
@@ -272,7 +270,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
             this,
             this.doc,
             this.props.DataDoc,
-            this.props.ContainingCollectionDoc,
+            undefined,
             undefined,
             addDoc,
             this.remove,
@@ -331,10 +329,10 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                     isDocumentActive={returnTrue}
                     addDocument={this.props.addDocument}
                     moveDocument={this.props.moveDocument}
+                    removeDocument={this.props.removeDocument}
                     addDocTab={this.props.addDocTab}
                     pinToPres={emptyFunction}
                     rootSelected={this.props.isSelected}
-                    removeDocument={this.props.removeDocument}
                     ScreenToLocalTransform={Transform.Identity}
                     PanelWidth={this.return35}
                     PanelHeight={this.return35}
@@ -347,8 +345,6 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                     docFilters={this.props.docFilters}
                     docRangeFilters={this.props.docRangeFilters}
                     searchFilterDocs={this.props.searchFilterDocs}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                 />
             </div>
         );
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index bc25ad43a..53fbcc3cc 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -279,7 +279,10 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             CollectionView: this,
         };
         return (
-            <div className={'collectionView'} onContextMenu={this.onContextMenu} style={{ pointerEvents: this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform && this.rootDoc._lockedPosition ? 'none' : undefined }}>
+            <div
+                className="collectionView"
+                onContextMenu={this.onContextMenu}
+                style={{ pointerEvents: this.props.DocumentView?.()?.props.docViewPath().lastElement()?.rootDoc?._viewType === CollectionViewType.Freeform && this.rootDoc._lockedPosition ? 'none' : undefined }}>
                 {this.showIsTagged()}
                 {this.renderSubView(this.collectionViewType, props)}
             </div>
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 458712999..ef8f395c5 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -425,8 +425,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     hideTitle={this.props.keyValue}
                     Document={this._document}
                     DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     onBrowseClick={MainView.Instance.exploreMode}
                     waitForDoubleClickToClick={MainView.Instance.waitForDoubleClick}
                     isContentActive={returnTrue}
@@ -580,8 +578,6 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                 <CollectionFreeFormView
                     Document={this.props.document}
                     CollectionView={undefined}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     docViewPath={returnEmptyDoclist}
                     childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
                     noOverlay={true} // don't render overlay Docs since they won't scale
@@ -603,7 +599,7 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                     ScreenToLocalTransform={Transform.Identity}
                     renderDepth={0}
                     whenChildContentsActiveChanged={emptyFunction}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     styleProvider={TabMinimapView.miniStyleProvider}
                     addDocTab={this.props.addDocTab}
                     pinToPres={TabDocView.PinDoc}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 75e76019e..8b1dfc767 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -42,7 +42,7 @@ export interface TreeViewProps {
     prevSibling?: Doc;
     document: Doc;
     dataDoc?: Doc;
-    containerCollection: Doc;
+    treeViewParent: Doc;
     renderDepth: number;
     dropAction: dropActionType;
     addDocTab: (doc: Doc, where: OpenWhere) => boolean;
@@ -143,7 +143,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         return this.validExpandViewTypes.includes(StrCast(this.doc.treeViewExpandedView)) ? StrCast(this.doc.treeViewExpandedView) : this.defaultExpandedView;
     }
     @computed get MAX_EMBED_HEIGHT() {
-        return NumCast(this.props.containerCollection.maxEmbedHeight, 200);
+        return NumCast(this.props.treeViewParent.maxEmbedHeight, 200);
     }
     @computed get dataDoc() {
         return this.props.document.treeViewChildrenOnRoot ? this.doc : this.doc[DataSym];
@@ -194,7 +194,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         const ind = this.dataDoc[key].indexOf(doc);
 
         const res = (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.RemoveDocFromList(this.dataDoc, key, doc), true);
-        res && ind > 0 && DocumentManager.Instance.getDocumentView(this.dataDoc[key][ind - 1], this.props.treeView.props.CollectionView)?.select(false);
+        res && ind > 0 && DocumentManager.Instance.getDocumentView(this.dataDoc[key][ind - 1], this.props.treeView.props.DocumentView?.())?.select(false);
         return res;
     };
 
@@ -385,7 +385,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         };
         const addDoc = inside ? localAdd : parentAddDoc;
         const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same') && moveDocument;
-        const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.containerCollection)?.freezeChildren).includes('add')) || forceAdd;
+        const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.freezeChildren).includes('add')) || forceAdd;
         if (canAdd) {
             this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = true);
             const res = UndoManager.RunInTempBatch(() => droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false));
@@ -406,7 +406,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     getTransform = () => this.refTransform(this._tref.current);
     embeddedPanelWidth = () => this.props.panelWidth() / (this.props.treeView.props.NativeDimScaling?.() || 1);
     embeddedPanelHeight = () => {
-        const layoutDoc = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ''))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc;
+        const layoutDoc = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc;
         return Math.min(
             layoutDoc[HeightSym](),
             this.MAX_EMBED_HEIGHT,
@@ -416,7 +416,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 return layoutDoc._fitWidth
                     ? !Doc.NativeHeight(layoutDoc)
                         ? NumCast(layoutDoc._height)
-                        : Math.min((this.embeddedPanelWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.containerCollection._height)))
+                        : Math.min((this.embeddedPanelWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.treeViewParent._height)))
                     : (this.embeddedPanelWidth() * layoutDoc[HeightSym]()) / layoutDoc[WidthSym]();
             })()
         );
@@ -452,7 +452,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     this,
                     doc,
                     undefined,
-                    this.props.containerCollection,
+                    this.props.treeViewParent,
                     this.props.prevSibling,
                     addDoc,
                     remDoc,
@@ -596,7 +596,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                                   this,
                                   this.layoutDoc,
                                   this.dataDoc,
-                                  this.props.containerCollection,
+                                  this.props.treeViewParent,
                                   this.props.prevSibling,
                                   addDoc,
                                   remDoc,
@@ -656,7 +656,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             this.onCheckedClick?.script.run(
                 {
                     this: this.doc.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.doc,
-                    heading: this.props.containerCollection.title,
+                    heading: this.props.treeViewParent.title,
                     checked: this.doc.treeViewChecked === 'check' ? 'x' : this.doc.treeViewChecked === 'x' ? 'remove' : 'check',
                     containingTreeView: this.props.treeView.props.Document,
                 },
@@ -724,9 +724,11 @@ export class TreeView extends React.Component<TreeViewProps> {
     };
 
     @observable headerEleWidth = 0;
-    @computed get headerElements() {
+    @computed get titleButtons() {
+        const customHeaderButtons = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations);
         return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? null : (
             <>
+                {customHeaderButtons} {/* e.g.,. hide button is set by dashboardStyleProvider */}
                 {this.doc.hideContextMenu ? null : (
                     <FontAwesomeIcon
                         title="context menu"
@@ -779,9 +781,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label }));
     };
 
-    onChildClick = () => {
-        return this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!);
-    };
+    onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!);
 
     onChildDoubleClick = () => ScriptCast(this.props.treeView.Document.treeViewChildDoubleClick, !this.props.treeView.outlineMode ? this._openScript?.() : null);
 
@@ -906,7 +906,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 styleProvider={this.titleStyleProvider}
                 enableDragWhenActive={true}
                 onClickScriptDisable="never" // tree docViews have a script to show fields, etc.
-                docViewPath={returnEmptyDoclist}
+                docViewPath={this.props.treeView.props.docViewPath}
                 treeViewDoc={this.props.treeView.props.Document}
                 addDocument={undefined}
                 addDocTab={this.props.addDocTab}
@@ -937,12 +937,8 @@ export class TreeView extends React.Component<TreeViewProps> {
                 docFilters={returnEmptyFilter}
                 docRangeFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
-                ContainingCollectionView={this.props.treeView.props.CollectionView}
-                ContainingCollectionDoc={this.props.treeView.props.Document}
             />
         );
-
-        const buttons = this.props.styleProvider?.(this.doc, { ...this.props.treeView.props, ContainingCollectionDoc: this.props.parentTreeView?.doc }, StyleProp.Decorations + (Doc.IsSystem(this.props.containerCollection) ? ':afterHeader' : ''));
         return (
             <>
                 <div
@@ -958,8 +954,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     {view}
                 </div>
                 <div className="treeView-rightButtons" ref={action((r: any) => r && (this.headerEleWidth = r.getBoundingClientRect().width))}>
-                    {buttons} {/* hide and lock buttons */}
-                    {this.headerElements}
+                    {this.titleButtons}
                 </div>
             </>
         );
@@ -1017,8 +1012,6 @@ export class TreeView extends React.Component<TreeViewProps> {
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionDoc={this.props.containerCollection}
-                    ContainingCollectionView={undefined}
                     addDocument={this.props.addDocument}
                     moveDocument={this.move}
                     removeDocument={this.props.removeDoc}
@@ -1131,7 +1124,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         childDocs: Doc[],
         treeView: CollectionTreeView,
         parentTreeView: CollectionTreeView | TreeView | undefined,
-        containerCollection: Doc,
+        treeViewParent: Doc,
         dataDoc: Doc | undefined,
         parentCollectionDoc: Doc | undefined,
         containerPrevSibling: Doc | undefined,
@@ -1162,19 +1155,19 @@ export class TreeView extends React.Component<TreeViewProps> {
         hierarchyIndex?: number[],
         renderCount?: number
     ) {
-        const viewSpecScript = Cast(containerCollection.viewSpecScript, ScriptField);
+        const viewSpecScript = Cast(treeViewParent.viewSpecScript, ScriptField);
         if (viewSpecScript) {
             childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result);
         }
 
-        const docs = TreeView.sortDocs(childDocs, StrCast(containerCollection.treeViewSortCriterion, TreeSort.None));
+        const docs = TreeView.sortDocs(childDocs, StrCast(treeViewParent.treeViewSortCriterion, TreeSort.None));
         const rowWidth = () => panelWidth() - treeBulletWidth() * (treeView.props.NativeDimScaling?.() || 1);
         const treeViewRefs = new Map<Doc, TreeView | undefined>();
         return docs
             .filter(child => child instanceof Doc)
             .map((child, i) => {
                 if (renderCount && i > renderCount) return null;
-                const pair = Doc.GetLayoutDataDocPair(containerCollection, dataDoc, child);
+                const pair = Doc.GetLayoutDataDocPair(treeViewParent, dataDoc, child);
                 if (!pair.layout || pair.data instanceof Promise) {
                     return null;
                 }
@@ -1192,10 +1185,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     }
                 };
                 const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1]));
-                const outdent =
-                    parentCollectionDoc?._viewType !== CollectionViewType.Tree
-                        ? undefined
-                        : (editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined);
+                const outdent = !parentCollectionDoc ? undefined : (editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined);
                 const addDocument = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false);
                 const childLayout = Doc.Layout(pair.layout);
                 const rowHeight = () => {
@@ -1208,7 +1198,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         ref={r => treeViewRefs.set(child, r ? r : undefined)}
                         document={pair.layout}
                         dataDoc={pair.data}
-                        containerCollection={containerCollection}
+                        treeViewParent={treeViewParent}
                         prevSibling={docs[i]}
                         // TODO: [AL] add these
                         hierarchyIndex={hierarchyIndex ? [...hierarchyIndex, i + 1] : undefined}
@@ -1220,7 +1210,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         onCheckedClick={onCheckedClick}
                         onChildClick={onChildClick}
                         renderDepth={renderDepth}
-                        removeDoc={StrCast(containerCollection.freezeChildren).includes('remove') ? undefined : remove}
+                        removeDoc={StrCast(treeViewParent.freezeChildren).includes('remove') ? undefined : remove}
                         addDocument={addDocument}
                         styleProvider={styleProvider}
                         panelWidth={rowWidth}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 7ae7be3c8..a3f5e73fb 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -262,7 +262,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     };
     selectDocuments = (docs: Doc[]) => {
         SelectionManager.DeselectAll();
-        docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView)).map(dv => dv && SelectionManager.SelectView(dv, true));
+        docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.DocumentView?.())).map(dv => dv && SelectionManager.SelectView(dv, true));
     };
     addDocument = (newBox: Doc | Doc[]) => {
         let retVal = false;
@@ -319,7 +319,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         // glr: freeform transform speed can be set by adjusting presTransition field - needs a way of knowing when presentation is not active...
         if (didMove) {
             const focusTime = options?.instant ? 0 : options.zoomTime ?? 500;
-            options.zoomScale && scale && (this.Document[this.scaleFieldKey] = scale);
+            (options.zoomScale || options.willZoomCentered) && scale && (this.Document[this.scaleFieldKey] = scale);
             this.setPan(panX, panY, focusTime, true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
             return focusTime;
         }
@@ -378,19 +378,17 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 1
             );
             if (sorted.length && refDoc && NumCast(sorted[0].layout.y) < NumCast(refDoc.y)) {
-                const topIndexed = NumCast(refDoc.y) < NumCast(sorted[0].layout.y) + NumCast(sorted[0].layout._height);
+                const topIndexed = NumCast(refDoc.y) < NumCast(sorted[0].layout.y) + NumCast(sorted[0].layout._height) / 2;
                 const deltay = sorted.length > 1 ? NumCast(refDoc.y) - (NumCast(sorted[0].layout.y) + (topIndexed ? 0 : NumCast(sorted[0].layout._height))) : 0;
                 const deltax = sorted.length > 1 ? NumCast(refDoc.x) - NumCast(sorted[0].layout.x) : 0;
 
                 let lastx = NumCast(refDoc.x);
                 let lasty = NumCast(refDoc.y) + (topIndexed ? 0 : NumCast(refDoc._height));
-                setTimeout(
-                    action(() =>
-                        sorted.slice(1).forEach((pair, i) => {
-                            lastx = pair.layout.x = lastx + deltax;
-                            lasty = (pair.layout.y = lasty + deltay) + (topIndexed ? 0 : NumCast(pair.layout._height));
-                        })
-                    )
+                runInAction(() =>
+                    sorted.slice(1).forEach((pair, i) => {
+                        lastx = pair.layout.x = lastx + deltax;
+                        lasty = (pair.layout.y = lasty + deltay) + (topIndexed ? 0 : NumCast(pair.layout._height));
+                    })
                 );
             }
         }
@@ -464,7 +462,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             const ptsParent = e instanceof PointerEvent ? e : e.targetTouches.item(0);
             if (ptsParent) {
                 const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.props.Document._useClusters ? NumCast(cd.cluster) : NumCast(cd.group, -1)) === cluster);
-                const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.props.CollectionView)!);
+                const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.props.DocumentView?.())!);
                 const { left, top } = clusterDocs[0].getBounds() || { left: 0, top: 0 };
                 const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? 'alias' : undefined);
                 de.moveDocument = this.props.moveDocument;
@@ -872,7 +870,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const eraserMax = { X: Math.max(lastPoint.X, currPoint.X), Y: Math.max(lastPoint.Y, currPoint.Y) };
 
         return this.childDocs
-            .map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView))
+            .map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.DocumentView?.()))
             .filter(inkView => inkView?.ComponentView instanceof InkingStroke)
             .map(inkView => ({ inkViewBounds: inkView!.getBounds(), inkStroke: inkView!.ComponentView as InkingStroke, inkView: inkView! }))
             .filter(
@@ -966,7 +964,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         this.childDocs
             .filter(doc => doc.type === DocumentType.INK && !doc.dontIntersect)
             .forEach(doc => {
-                const otherInk = DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView)?.ComponentView as InkingStroke;
+                const otherInk = DocumentManager.Instance.getDocumentView(doc, this.props.DocumentView?.())?.ComponentView as InkingStroke;
                 const { inkData: otherInkData } = otherInk?.inkScaledData() ?? { inkData: [] };
                 const otherScreenPts = otherInkData.map(point => otherInk.ptToScreen(point));
                 const otherCtrlPts = otherScreenPts.map(spt => (ink.ComponentView as InkingStroke).ptFromScreen(spt));
@@ -1121,7 +1119,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     nudge = (x: number, y: number, nudgeTime: number = 500) => {
-        if (this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform || this.props.ContainingCollectionDoc._panX !== undefined) {
+        const collectionDoc = this.props.docViewPath().lastElement().rootDoc;
+        if (collectionDoc?._viewType !== CollectionViewType.Freeform || collectionDoc._panX !== undefined) {
             this.setPan(
                 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(),
@@ -1256,8 +1255,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 replica={entry.replica}
                 suppressSetHeight={this.layoutEngine ? true : false}
                 renderCutoffProvider={this.renderCutoffProvider}
-                ContainingCollectionView={this.props.CollectionView}
-                ContainingCollectionDoc={this.props.Document}
                 CollectionFreeFormView={this}
                 LayoutTemplate={childLayout.z ? undefined : this.props.childLayoutTemplate}
                 LayoutTemplateString={childLayout.z ? undefined : this.props.childLayoutString}
@@ -1779,7 +1776,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 const lines = text.split('\n');
                 const height = 30 + 15 * lines.length;
 
-                this.props.ContainingCollectionView?.addDocument(Docs.Create.TextDocument(text, { title: lines[0], x: NumCast(this.layoutDoc.x) + NumCast(this.layoutDoc._width) + 20, y: NumCast(this.layoutDoc.y), _width: 200, _height: height }));
+                this.addDocument(Docs.Create.TextDocument(text, { title: lines[0], x: NumCast(this.layoutDoc.x) + NumCast(this.layoutDoc._width) + 20, y: NumCast(this.layoutDoc.y), _width: 200, _height: height }));
             }
         }
     };
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index c7d9b6619..97eed7752 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -209,8 +209,6 @@ export class CollectionLinearView extends CollectionSubView() {
                     docFilters={this.props.docFilters}
                     docRangeFilters={this.props.docRangeFilters}
                     searchFilterDocs={this.props.searchFilterDocs}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     hideResizeHandles={true}
                 />
             </div>
@@ -251,8 +249,7 @@ export class CollectionLinearView extends CollectionSubView() {
                                 self: this.rootDoc,
                                 _readOnly_: false,
                                 scriptContext: this.props.scriptContext,
-                                thisContainer: this.props.ContainingCollectionDoc,
-                                documentView: this.props.docViewPath().lastElement(),
+                                documentView: this.props.DocumentView?.(),
                             });
                             this.layoutDoc.linearViewIsExpanded = this.addMenuToggle.current!.checked;
                         })}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index b73b1d779..78d3d1b6e 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -262,8 +262,6 @@ export class CollectionMulticolumnView extends CollectionSubView() {
                 docFilters={this.childDocFilters}
                 docRangeFilters={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
-                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                ContainingCollectionView={this.props.CollectionView}
                 dontRegisterView={this.props.dontRegisterView}
                 addDocument={this.props.addDocument}
                 moveDocument={this.props.moveDocument}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 0cca83803..4d61dc272 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -261,8 +261,6 @@ export class CollectionMultirowView extends CollectionSubView() {
                 docFilters={this.childDocFilters}
                 docRangeFilters={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
-                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                ContainingCollectionView={this.props.CollectionView}
                 dontRegisterView={this.props.dontRegisterView}
                 addDocument={this.props.addDocument}
                 moveDocument={this.props.moveDocument}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index fd9bcf681..6d5a73e55 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -793,7 +793,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 fitContentsToBox={returnTrue}
                                 dontCenter={'y'}
                                 onClickScriptDisable="always"
-                                focus={DocUtils.DefaultFocus}
+                                focus={emptyFunction}
                                 renderDepth={this.props.renderDepth + 1}
                                 rootSelected={this.rootSelected}
                                 PanelWidth={this.previewWidthFunc}
@@ -806,8 +806,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 searchFilterDocs={this.searchFilterDocs}
                                 styleProvider={DefaultStyleProvider}
                                 docViewPath={returnEmptyDoclist}
-                                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                                ContainingCollectionView={this.props.CollectionView}
                                 moveDocument={this.props.moveDocument}
                                 addDocument={this.addRow}
                                 removeDocument={this.props.removeDocument}
@@ -849,8 +847,6 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 Document={doc}
                                 DataDoc={dataDoc}
                                 renderDepth={this.props.schema.props.renderDepth + 1}
-                                ContainingCollectionView={this.props.schema.props.CollectionView}
-                                ContainingCollectionDoc={this.props.schema.Document}
                                 PanelWidth={this.tableWidthFunc}
                                 PanelHeight={this.rowHeightFunc}
                                 styleProvider={DefaultStyleProvider}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 2defaae00..856537927 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -29,7 +29,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
     }
 
     @computed get schemaDoc() {
-        return this.props.ContainingCollectionDoc!;
+        return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc;
     }
 
     @computed get rowIndex() {
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 13e45963e..5f8ffe8b0 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -28,8 +28,6 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
             docViewPath: returnEmptyDoclist,
-            ContainingCollectionView: undefined,
-            ContainingCollectionDoc: undefined,
             fieldKey: this.props.fieldKey,
             rootSelected: returnFalse,
             isSelected: returnFalse,
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 29e7cd3ad..d703c9595 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -44,25 +44,10 @@ export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: Docume
         }
 
         const dragData = new DragManager.DocumentDragData(moddrag.length ? moddrag : draggedDocs);
-        dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => {
-            docView.props.removeDocument?.(doc);
-            addDocument(doc);
-            return true;
-        };
-        const containingView = docView.props.ContainingCollectionView;
-        const finishDrag = (e: DragManager.DragCompleteEvent) =>
-            e.docDragData &&
-            (e.docDragData.droppedDocuments = dragData.draggedDocuments.reduce((droppedDocs, d) => {
-                const dvs = DocumentManager.Instance.getDocumentViews(d).filter(dv => dv.props.ContainingCollectionView === containingView);
-                if (dvs.length) {
-                    dvs.forEach(dv => droppedDocs.push(dv.props.Document));
-                } else {
-                    droppedDocs.push(Doc.MakeAlias(d));
-                }
-                return droppedDocs;
-            }, [] as Doc[]));
+        dragData.canEmbed = true;
+        dragData.moveDocument = (docView.props.docViewPath().lastElement()?.ComponentView as any)?.props.CollectionView?.moveDocument; // this is equal to docView.props.moveDocument, but moveDocument is not a defined prop of a DocumentView .. but maybe it should be?
 
-        DragManager.StartDrag([dragEle], dragData, downX, downY, undefined, finishDrag);
+        DragManager.StartDocumentDrag([dragEle], dragData, downX, downY, undefined);
     }
 }
 
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index 7bdace2b6..5f2d4a7b6 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -85,15 +85,13 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
                         PanelWidth={this.getPWidth}
                         PanelHeight={this.getPHeight}
                         renderDepth={0}
-                        focus={DocUtils.DefaultFocus}
+                        focus={emptyFunction}
                         docViewPath={returnEmptyDoclist}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
                         docFilters={returnEmptyFilter}
                         docRangeFilters={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
                     />
                 </div>
             </div>
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 9bdb2cee7..24b9f3b25 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -160,8 +160,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     }
 
     @action public float = () => {
-        const { Document: topDoc, ContainingCollectionView: container } = this.props;
-        const screenXf = container?.screenToLocalTransform();
+        const topDoc = this.rootDoc;
+        const containerDocView = this.props.docViewPath().lastElement();
+        const screenXf = containerDocView?.screenToLocalTransform();
         if (screenXf) {
             SelectionManager.DeselectAll();
             if (topDoc.z) {
@@ -178,7 +179,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 topDoc.x = fpt[0];
                 topDoc.y = fpt[1];
             }
-            setTimeout(() => SelectionManager.SelectView(DocumentManager.Instance.getDocumentView(topDoc, container)!, false), 0);
+            setTimeout(() => SelectionManager.SelectView(DocumentManager.Instance.getDocumentView(topDoc, containerDocView), false), 0);
         }
     };
 
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index dbcfe43cf..76a5ce7b3 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -154,7 +154,6 @@ export class DocumentContentsView extends React.Component<
             // these are the properties in  DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews
             'hideResizeHandles',
             'hideTitle',
-            'treeViewDoc',
             'contentPointerEvents',
             'radialMenu',
             'LayoutTemplateString',
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index df3299eef..47705d53d 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -142,7 +142,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
             } else if (startLink !== endLink) {
                 endLink = endLinkView?.docView?._componentView?.getAnchor?.(true, pinProps) || endLink;
                 startLink = DocumentLinksButton.StartLinkView?.docView?._componentView?.getAnchor?.(true) || startLink;
-                const linkDoc = DocUtils.MakeLink(startLink, endLink, { linkRelationship: DocumentLinksButton.AnnotationId ? 'hypothes.is annotation' : undefined }, undefined, true);
+                const linkDoc = DocUtils.MakeLink(startLink, endLink, { linkRelationship: DocumentLinksButton.AnnotationId ? 'hypothes.is annotation' : undefined });
 
                 LinkManager.currentLink = linkDoc;
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f161a7b9b..be07f1fe5 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -148,8 +148,6 @@ export interface DocumentViewSharedProps {
     DataDoc?: Doc;
     contentBounds?: () => undefined | { x: number; y: number; r: number; b: number };
     fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _fitContentsToBox property on a Document
-    ContainingCollectionView: Opt<CollectionView>;
-    ContainingCollectionDoc: Opt<Doc>;
     suppressSetHeight?: boolean;
     thumbShown?: () => boolean;
     setContentView?: (view: DocComponentView) => any;
@@ -179,6 +177,7 @@ export interface DocumentViewSharedProps {
     ScreenToLocalTransform: () => Transform;
     bringToFront: (doc: Doc, sendToBack?: boolean) => void;
     canEmbedOnDrag?: boolean;
+    treeViewDoc?: Doc;
     xPadding?: number;
     yPadding?: number;
     dropAction?: dropActionType;
@@ -210,7 +209,6 @@ export interface DocumentViewProps extends DocumentViewSharedProps {
     hideOpenButton?: boolean;
     hideDeleteButton?: boolean;
     hideLinkAnchors?: boolean;
-    treeViewDoc?: Doc;
     isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events
     isContentActive: () => boolean | undefined; // whether document contents should handle pointer events
     contentPointerEvents?: string; // pointer events allowed for content of a document view.  eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
@@ -429,7 +427,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                             this: this.layoutDoc,
                             self: this.rootDoc,
                             scriptContext: this.props.scriptContext,
-                            thisContainer: this.props.ContainingCollectionDoc,
                             documentView: this.props.DocumentView(),
                             clientX, clientY,  altKey,  shiftKey,  ctrlKey,
                             value: undefined,
@@ -456,7 +453,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                                 self: this.rootDoc,
                                 _readOnly_: false,
                                 scriptContext: this.props.scriptContext,
-                                thisContainer: this.props.ContainingCollectionDoc,
                                 documentView: this.props.DocumentView(),
                                 clientX,
                                 clientY,
@@ -605,7 +601,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 }
                 if (de.complete.annoDragData || this.rootDoc !== linkdrag.linkSourceDoc.context) {
                     const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.(true) ?? this.rootDoc;
-                    de.complete.linkDocument = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, undefined, [de.x, de.y - 50]);
+                    de.complete.linkDocument = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, [de.x, de.y - 50]);
                 }
             }
         }
@@ -697,7 +693,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template   ', event: () => this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' });
             !appearance && appearanceItems.length && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' });
 
-            if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._viewType !== CollectionViewType.Docking && this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Tree) {
+            if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._viewType !== CollectionViewType.Docking && this.props.docViewPath().lastElement()?.rootDoc?._viewType !== CollectionViewType.Tree) {
                 const existingOnClick = cm.findByDescription('OnClick...');
                 const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : [];
 
@@ -1446,7 +1442,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     scaleToScreenSpace = () => (1 / (this.props.NativeDimScaling?.() || 1)) * this.screenToLocalTransform().Scale;
     docViewPathFunc = () => this.docViewPath;
     isSelected = (outsideReaction?: boolean) => SelectionManager.IsSelected(this, outsideReaction);
-    select = (extendSelection: boolean) => SelectionManager.SelectView(this, !SelectionManager.Views().some(v => v.props.Document === this.props.ContainingCollectionDoc) && extendSelection);
+    select = (extendSelection: boolean) => SelectionManager.SelectView(this, extendSelection);
     NativeWidth = () => this.effectiveNativeWidth;
     NativeHeight = () => this.effectiveNativeHeight;
     PanelWidth = () => this.panelWidth;
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 8d3534a5c..86779e0dd 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -32,6 +32,7 @@ export interface FieldViewProps extends DocumentViewSharedProps {
     // See currentUserUtils headerTemplate for examples of creating text boxes from html which set some of these fields
     // Also, see InkingStroke for examples of creating text boxes from render() methods which set some of these fields
     backgroundColor?: string;
+    treeViewDoc?: Doc;
     color?: string;
     fontSize?: number;
     height?: number;
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 94434dce7..7ea6d42ff 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -61,8 +61,6 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
             docViewPath: returnEmptyDoclist,
-            ContainingCollectionView: undefined,
-            ContainingCollectionDoc: undefined,
             fieldKey: this.props.keyName,
             rootSelected: returnFalse,
             isSelected: returnFalse,
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index fcc5b6975..c58b5dd8c 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -271,14 +271,12 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                             docFilters={returnEmptyFilter}
                             docRangeFilters={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
-                            ContainingCollectionDoc={undefined}
-                            ContainingCollectionView={undefined}
                             renderDepth={0}
                             suppressSetHeight={true}
                             PanelWidth={this.width}
                             PanelHeight={this.height}
                             pointerEvents={returnNone}
-                            focus={DocUtils.DefaultFocus}
+                            focus={emptyFunction}
                             whenChildContentsActiveChanged={returnFalse}
                             ignoreAutoHeight={true} // need to ignore autoHeight otherwise autoHeight text boxes will expand beyond the preview panel size.
                             bringToFront={returnFalse}
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index db11a7776..e015024fd 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -305,8 +305,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                             addDocument={returnFalse}
                             CollectionView={undefined}
                             ScreenToLocalTransform={this.props.ScreenToLocalTransform}
-                            renderDepth={this.props.renderDepth + 1}
-                            ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
+                            renderDepth={this.props.renderDepth + 1}>
                             <>
                                 {this.threed}
                                 {this.content}
@@ -330,7 +329,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                                 moveDocument={returnFalse}
                                 addDocument={returnFalse}
                                 renderDepth={this.props.renderDepth + 1}
-                                ContainingCollectionDoc={this.props.ContainingCollectionDoc}></FormattedTextBox>
+                            />
                         )}
                     </div>
                 </div>
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index 8eacfbc51..1a75a7e76 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -568,12 +568,12 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b
     if (selectedViews.length) {
         if (checkResult) {
             const selView = selectedViews.lastElement();
-            const layoutFrameNumber = Cast(selView.props.ContainingCollectionDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
+            const layoutFrameNumber = Cast(selView.props.docViewPath().lastElement()?.rootDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
             const contentFrameNumber = Cast(selView.rootDoc?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
             return CollectionFreeFormDocumentView.getStringValues(selView?.rootDoc, contentFrameNumber).backgroundColor ?? 'transparent';
         }
         selectedViews.forEach(dv => {
-            const layoutFrameNumber = Cast(dv.props.ContainingCollectionDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
+            const layoutFrameNumber = Cast(dv.props.docViewPath().lastElement()?.rootDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
             const contentFrameNumber = Cast(dv.rootDoc?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
             if (contentFrameNumber !== undefined) {
                 CollectionFreeFormDocumentView.setStringValues(contentFrameNumber, dv.rootDoc, { backgroundColor: color });
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index c00ab6a7e..b31fc01ff 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -9,10 +9,9 @@ import { DocServer } from '../../../DocServer';
 import { Docs, DocUtils } from '../../../documents/Documents';
 import { ColorScheme } from '../../../util/SettingsManager';
 import { Transform } from '../../../util/Transform';
-import { DocumentView } from '../DocumentView';
+import { DocFocusOptions, DocumentView } from '../DocumentView';
 import { FormattedTextBox } from './FormattedTextBox';
 import React = require('react');
-import { SelectionManager } from '../../../util/SelectionManager';
 
 export class DashDocView {
     dom: HTMLSpanElement; // container for label and value
@@ -151,7 +150,7 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
         const { scale, translateX, translateY } = Utils.GetScreenTransform(this._spanRef.current);
         return new Transform(-translateX, -translateY, 1).scale(1 / scale);
     };
-    outerFocus = (target: Doc) => this._textBox.props.focus(this._textBox.props.Document, {}); // ideally, this would scroll to show the focus target
+    outerFocus = (target: Doc, options: DocFocusOptions) => this._textBox.focus(target, options); // ideally, this would scroll to show the focus target
 
     onKeyDown = (e: any) => {
         e.stopPropagation();
@@ -212,8 +211,6 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
                     docFilters={this.props.tbox?.props.docFilters}
                     docRangeFilters={this.props.tbox?.props.docRangeFilters}
                     searchFilterDocs={this.props.tbox?.props.searchFilterDocs}
-                    ContainingCollectionView={this._textBox.props.ContainingCollectionView}
-                    ContainingCollectionDoc={this._textBox.props.ContainingCollectionDoc}
                 />
             </div>
         );
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index f23426bb3..c43206629 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -235,10 +235,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
     };
 
     createPivotForField = (e: React.MouseEvent) => {
-        let container = this.props.tbox.props.ContainingCollectionView;
-        while (container?.props.Document.isTemplateForField || container?.props.Document.isTemplateDoc) {
-            container = container.props.ContainingCollectionView;
-        }
+        let container = this.props.tbox.props.DocumentView?.().props.docViewPath().lastElement();
         if (container) {
             const alias = Doc.MakeAlias(container.props.Document);
             alias._viewType = CollectionViewType.Time;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 677c4662b..bc2a5d797 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -541,7 +541,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 // embed document when dragg marked as embed
             } else if (de.embedKey) {
                 const target = dragData.droppedDocuments[0];
-                target._fitContentsToBox = true;
                 const node = schema.nodes.dashDoc.create({
                     width: target[WidthSym](),
                     height: target[HeightSym](),
@@ -552,6 +551,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 if (!['alias', 'copy'].includes((dragData.dropAction ?? '') as any)) {
                     dragData.removeDocument?.(dragData.draggedDocuments[0]);
                 }
+                target._fitContentsToBox = true;
+                target.context = this.rootDoc;
                 const view = this._editorView!;
                 view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node));
                 e.stopPropagation();
@@ -880,7 +881,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         if (this._editorView && this._recordingStart) {
             if (this._break) {
                 const textanchorFunc = () => {
-                    const tanch = Docs.Create.TextanchorDocument({ title: 'dictation anchor' });
+                    const tanch = Docs.Create.TextanchorDocument({ title: 'dictation anchor', unrendered: true });
                     return this.addDocument(tanch) ? tanch : undefined;
                 };
                 const link = DocUtils.MakeLinkToActiveAudio(textanchorFunc, false).lastElement();
@@ -956,7 +957,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             let hadStart = start !== 0;
             frag.forEach((node, index) => {
                 const examinedNode = findAnchorNode(node, editor);
-                if (examinedNode?.node && (examinedNode.node.textContent || examinedNode.node.type === this._editorView?.state.schema.nodes.audiotag)) {
+                if (examinedNode?.node && (examinedNode.node.textContent || examinedNode.node.type === this._editorView?.state.schema.nodes.dashDoc || examinedNode.node.type === this._editorView?.state.schema.nodes.audiotag)) {
                     nodes.push(examinedNode.node);
                     !hadStart && (start = index + examinedNode.start);
                     hadStart = true;
@@ -971,9 +972,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 }
                 return undefined;
             }
+            if (node.type === this._editorView?.state.schema.nodes.dashDoc) {
+                if (node.attrs.docId === textAnchorId) {
+                    return { node, start: 0 };
+                }
+                return undefined;
+            }
             if (!node.isText) {
                 const content = findAnchorFrag(node.content, editor);
-                return { node: node.copy(content.frag), start: content.start };
+                if (content.frag.childCount) return { node: content.frag.childCount ? content.frag.child(0) : node, start: content.start };
             }
             const marks = [...node.marks];
             const linkIndex = marks.findIndex(mark => mark.type === editor.state.schema.marks.linkAnchor);
@@ -987,7 +994,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             const ret = findAnchorFrag(editor.state.doc.content, editor);
 
             const content = (ret.frag as any)?.content;
-            if ((ret.frag.size > 2 || (content?.length && content[0].type === this._editorView.state.schema.nodes.audiotag)) && ret.start >= 0) {
+            if ((ret.frag.size || (content?.length && content[0].type === this._editorView.state.schema.nodes.dashDoc) || (content?.length && content[0].type === this._editorView.state.schema.nodes.audiotag)) && ret.start >= 0) {
                 !options.instant && (this._focusSpeed = focusSpeed);
                 let selection = TextSelection.near(editor.state.doc.resolve(ret.start)); // default to near the start
                 if (ret.frag.firstChild) {
@@ -998,6 +1005,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 addStyleSheetRule(FormattedTextBox._highlightStyleSheet, `${escAnchorId}`, { background: 'yellow', transform: 'scale(3)', 'transform-origin': 'left bottom' });
                 setTimeout(() => (this._focusSpeed = undefined), this._focusSpeed);
                 setTimeout(() => clearStyleSheetRules(FormattedTextBox._highlightStyleSheet), Math.max(this._focusSpeed || 0, 3000));
+                return focusSpeed;
+            } else {
+                return this.props.focus(this.rootDoc, options);
             }
         }
     };
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 3589a9065..807a19771 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -2457,7 +2457,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         {mode !== CollectionViewType.Invalid ? (
                             <CollectionView
                                 {...this.props}
-                                ContainingCollectionDoc={this.props.Document}
                                 PanelWidth={this.props.PanelWidth}
                                 PanelHeight={this.panelHeight}
                                 childIgnoreNativeSize={true}
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 92696240b..502eef373 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -39,7 +39,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
     // Idea: this boolean will determine whether to automatically show the video when this preselement is selected.
     // @observable static showVideo: boolean = false;
     @computed get indexInPres() {
-        return DocListCast(this.presBox[StrCast(this.presBox.presFieldKey, 'data')]).indexOf(this.rootDoc);
+        return DocListCast(this.presBox?.[StrCast(this.presBox.presFieldKey, 'data')]).indexOf(this.rootDoc);
     } // the index field is where this document is in the presBox display list (since this value is different for each presentation element, the value can't be stored on the layout template which is used by all display elements)
     @computed get expandViewHeight() {
         return 100;
@@ -51,11 +51,10 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return this.presBoxView?.selectedArray;
     }
     @computed get presBoxView() {
-        const vpath = this.props.docViewPath();
-        return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as PresBox) : undefined;
+        return this.props.DocumentView?.()?.props.docViewPath().lastElement()?.ComponentView as PresBox;
     }
     @computed get presBox() {
-        return this.props.ContainingCollectionDoc!;
+        return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc;
     }
     @computed get targetDoc() {
         return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc;
@@ -110,14 +109,12 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     docFilters={this.props.docFilters}
                     docRangeFilters={this.props.docRangeFilters}
                     searchFilterDocs={this.props.searchFilterDocs}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     rootSelected={returnTrue}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
                     fitContentsToBox={returnTrue}
                     moveDocument={this.props.moveDocument!}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     whenChildContentsActiveChanged={returnFalse}
                     addDocTab={returnFalse}
                     pinToPres={returnFalse}
@@ -195,7 +192,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const dragData = new DragManager.DocumentDragData(this.presBoxView?.sortArray() ?? []);
         if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.rootDoc);
         dragData.dropAction = 'move';
-        dragData.treeViewDoc = this.presBox._viewType === CollectionViewType.Tree ? this.props.ContainingCollectionDoc : undefined; // this.props.DocumentView?.()?.props.treeViewDoc;
+        dragData.treeViewDoc = this.presBox?._viewType === CollectionViewType.Tree ? this.presBox : undefined; // this.props.DocumentView?.()?.props.treeViewDoc;
         dragData.moveDocument = this.props.moveDocument;
         const dragItem: HTMLElement[] = [];
         if (dragArray.length === 1) {
@@ -269,7 +266,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
     @undoBatch
     removeItem = action((e: React.MouseEvent) => {
         e.stopPropagation();
-        if (this.indexInPres < (this.presBoxView?.itemIndex || 0)) {
+        if (this.presBox && this.indexInPres < (this.presBoxView?.itemIndex || 0)) {
             this.presBox.itemIndex = (this.presBoxView?.itemIndex || 0) - 1;
         }
         this.props.removeDocument?.(this.rootDoc);
@@ -406,15 +403,15 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
     @computed
     get toolbarWidth(): number {
         const presBoxDocView = DocumentManager.Instance.getDocumentView(this.presBox);
-        let width: number = NumCast(this.presBox._width);
+        let width: number = NumCast(this.presBox?._width);
         if (presBoxDocView) width = presBoxDocView.props.PanelWidth();
         if (width === 0) width = 300;
         return width;
     }
 
     @computed get presButtons() {
-        const presBox: Doc = this.presBox; //presBox
-        const presBoxColor: string = StrCast(presBox._backgroundColor);
+        const presBox = this.presBox; //presBox
+        const presBoxColor: string = StrCast(presBox?._backgroundColor);
         const presColorBool: boolean = presBoxColor ? presBoxColor !== Colors.WHITE && presBoxColor !== 'transparent' : false;
         const targetDoc: Doc = this.targetDoc;
         const activeItem: Doc = this.rootDoc;
@@ -494,10 +491,10 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
 
     @computed get mainItem() {
         const isSelected: boolean = this.selectedArray?.has(this.rootDoc) ? true : false;
-        const isCurrent: boolean = this.presBox._itemIndex === this.indexInPres;
+        const isCurrent: boolean = this.presBox?._itemIndex === this.indexInPres;
         const miniView: boolean = this.toolbarWidth <= 110;
-        const presBox: Doc = this.presBox; //presBox
-        const presBoxColor: string = StrCast(presBox._backgroundColor);
+        const presBox = this.presBox; //presBox
+        const presBoxColor: string = StrCast(presBox?._backgroundColor);
         const presColorBool: boolean = presBoxColor ? presBoxColor !== Colors.WHITE && presBoxColor !== 'transparent' : false;
         const activeItem: Doc = this.rootDoc;
 
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index f2e9be61d..d63c25dbe 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -46,7 +46,7 @@ export class TopBar extends React.Component {
         return (
             <div className="topbar-left">
                 {Doc.ActiveDashboard ? (
-                    <IconButton onClick={this.navigateToHome} icon={<FontAwesomeIcon icon="home" />} isCircle={true} hoverStyle="gray" color={this.textColor} />
+                    <IconButton onClick={this.navigateToHome} icon={<FontAwesomeIcon icon="home" />} color={this.textColor} />
                 ) : (
                     <div className="logo-container">
                         <img className="logo" src="/assets/medium-blue-light-blue-circle.png" alt="dash logo"></img>
@@ -55,18 +55,7 @@ export class TopBar extends React.Component {
                     </div>
                 )}
                 {Doc.ActiveDashboard && (
-                    <Button
-                        text="Explore"
-                        tooltip="Browsing mode for directly navigating to documents"
-                        fontSize={FontSize.SECONDARY}
-                        isActive={MainView.Instance._exploreMode}
-                        size={Size.SMALL}
-                        color={this.textColor}
-                        borderRadius={5}
-                        hoverStyle="gray"
-                        iconPosition="right"
-                        onClick={action(() => (MainView.Instance._exploreMode = !MainView.Instance._exploreMode))}
-                    />
+                    <Button text="Explore" tooltip="Browsing mode for directly navigating to documents" size={Size.SMALL} color={this.textColor} onClick={action(() => (MainView.Instance._exploreMode = !MainView.Instance._exploreMode))} />
                 )}
             </div>
         );
@@ -94,13 +83,8 @@ export class TopBar extends React.Component {
                 <Button
                     text={StrCast(Doc.ActiveDashboard.title)}
                     tooltip="Browsing mode for directly navigating to documents"
-                    fontSize={FontSize.SECONDARY}
                     size={Size.SMALL}
                     color={'white'}
-                    type="outline"
-                    backgroundColor={Colors.MEDIUM_BLUE}
-                    borderRadius={5}
-                    hoverStyle="none"
                     onClick={(e: React.MouseEvent) => {
                         const dashView = Doc.ActiveDashboard && DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard);
                         ContextMenu.Instance.addItem({ description: 'Open Dashboard View', event: this.navigateToHome, icon: 'edit' });
@@ -121,21 +105,13 @@ export class TopBar extends React.Component {
                     onClick={() => {
                         SharingManager.Instance.open(undefined, Doc.ActiveDashboard);
                     }}
-                    type="outline"
-                    fontSize={FontSize.SECONDARY}
                     size={Size.SMALL}
-                    borderRadius={5}
-                    hoverStyle="gray"
                 />
                 {!Doc.noviceMode && (
                     <IconButton
-                        fontSize={FontSize.SECONDARY}
-                        isCircle={true}
                         tooltip="Work on a copy of the dashboard layout"
                         size={Size.SMALL}
                         color={this.textColor}
-                        borderRadius={Borders.STANDARD}
-                        hoverStyle="gray"
                         onClick={async () => {
                             const batch = UndoManager.StartBatch('snapshot');
                             await DashboardView.snapshotDashboard();
@@ -156,26 +132,9 @@ export class TopBar extends React.Component {
     @computed get topbarRight() {
         return (
             <div className="topbar-right">
-                <IconButton size={Size.SMALL} isCircle={true} color={Colors.LIGHT_GRAY} backgroundColor={Colors.DARK_GRAY} hoverStyle="gray" onClick={() => ReportManager.Instance.open()} icon={<FaBug />} />
-                <IconButton
-                    size={Size.SMALL}
-                    isCircle={true}
-                    color={Colors.LIGHT_GRAY}
-                    backgroundColor={Colors.DARK_GRAY}
-                    hoverStyle="gray"
-                    onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')}
-                    icon={<FontAwesomeIcon icon="question-circle" />}
-                />
-                <IconButton
-                    size={Size.SMALL}
-                    isCircle={true}
-                    color={Colors.LIGHT_GRAY}
-                    backgroundColor={Colors.DARK_GRAY}
-                    hoverStyle="gray"
-                    isActive={SettingsManager.Instance.isOpen}
-                    onClick={() => SettingsManager.Instance.open()}
-                    icon={<FontAwesomeIcon icon="cog" />}
-                />
+                <IconButton size={Size.SMALL} color={Colors.LIGHT_GRAY} onClick={() => ReportManager.Instance.open()} icon={<FaBug />} />
+                <IconButton size={Size.SMALL} color={Colors.LIGHT_GRAY} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')} icon={<FontAwesomeIcon icon="question-circle" />} />
+                <IconButton size={Size.SMALL} color={Colors.LIGHT_GRAY} onClick={() => SettingsManager.Instance.open()} icon={<FontAwesomeIcon icon="cog" />} />
                 {/* <Button text={'Logout'} borderRadius={5} hoverStyle={'gray'} backgroundColor={Colors.DARK_GRAY} color={this.textColor} fontSize={FontSize.SECONDARY} onClick={() => window.location.assign(Utils.prepend('/logout'))} /> */}
             </div>
         );
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index 64baa351c..a0b437354 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -13,13 +13,18 @@ import { listSpec } from '../fields/Schema';
 import { Cast, FieldValue } from '../fields/Types';
 import { nullAudio } from '../fields/URLField';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, emptyPath } from '../Utils';
-import "./ImageUpload.scss";
+import './ImageUpload.scss';
 import { MobileInterface } from './MobileInterface';
 import React = require('react');
 
 @observer
 export class AudioUpload extends React.Component {
-    @observable public _audioCol: Doc = FieldValue(Cast(Docs.Create.FreeformDocument([Cast(Docs.Create.AudioDocument(nullAudio, { title: "mobile audio", _width: 500, _height: 100 }), Doc) as Doc], { title: "mobile audio", _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: "0 0" }), Doc)) as Doc;
+    @observable public _audioCol: Doc = FieldValue(
+        Cast(
+            Docs.Create.FreeformDocument([Cast(Docs.Create.AudioDocument(nullAudio, { title: 'mobile audio', _width: 500, _height: 100 }), Doc) as Doc], { title: 'mobile audio', _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: '0 0' }),
+            Doc
+        )
+    ) as Doc;
 
     /**
      * Handles the onclick functionality for the 'Restart' button
@@ -28,25 +33,36 @@ export class AudioUpload extends React.Component {
     @action
     clearUpload = () => {
         for (let i = 1; i < 8; i++) {
-            this.setOpacity(i, "0.2");
+            this.setOpacity(i, '0.2');
         }
-        this._audioCol = FieldValue(Cast(
-            Docs.Create.FreeformDocument(
-                [Cast(Docs.Create.AudioDocument(nullAudio, {
-                    title: "mobile audio",
-                    _width: 500,
-                    _height: 100
-                }), Doc) as Doc], { title: "mobile audio", _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: "0 0" }), Doc)) as Doc;
-    }
+        this._audioCol = FieldValue(
+            Cast(
+                Docs.Create.FreeformDocument(
+                    [
+                        Cast(
+                            Docs.Create.AudioDocument(nullAudio, {
+                                title: 'mobile audio',
+                                _width: 500,
+                                _height: 100,
+                            }),
+                            Doc
+                        ) as Doc,
+                    ],
+                    { title: 'mobile audio', _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: '0 0' }
+                ),
+                Doc
+            )
+        ) as Doc;
+    };
 
-    /** 
+    /**
      * Handles the onClick of the 'Close' button
      * Reset upload interface and toggle audio
      */
     closeUpload = () => {
         this.clearUpload();
         MobileInterface.Instance.toggleAudio();
-    }
+    };
 
     /**
      * Handles the on click of the 'Upload' button.
@@ -57,14 +73,14 @@ export class AudioUpload extends React.Component {
         const audioDoc = this._audioCol;
         const data = Cast(audioRightSidebar.data, listSpec(Doc));
         for (let i = 1; i < 8; i++) {
-            setTimeout(() => this.setOpacity(i, "1"), i * 200);
+            setTimeout(() => this.setOpacity(i, '1'), i * 200);
         }
         if (data) {
             data.push(audioDoc);
         }
         // Resets uploader after 3 seconds
         setTimeout(this.clearUpload, 3000);
-    }
+    };
 
     // Returns the upload audio menu
     private get uploadInterface() {
@@ -72,11 +88,13 @@ export class AudioUpload extends React.Component {
             <>
                 <ContextMenu />
                 <DictationOverlay />
-                <div style={{ display: "none" }}><RichTextMenu key="rich" /></div>
+                <div style={{ display: 'none' }}>
+                    <RichTextMenu key="rich" />
+                </div>
                 <div className="closeUpload" onClick={() => this.closeUpload()}>
-                    <FontAwesomeIcon icon="window-close" size={"lg"} />
+                    <FontAwesomeIcon icon="window-close" size={'lg'} />
                 </div>
-                <FontAwesomeIcon icon="microphone" size="lg" style={{ fontSize: "130" }} />
+                <FontAwesomeIcon icon="microphone" size="lg" style={{ fontSize: '130' }} />
                 <div className="audioUpload_cont">
                     <DocumentView
                         Document={this._audioCol}
@@ -96,12 +114,10 @@ export class AudioUpload extends React.Component {
                         isDocumentActive={returnTrue}
                         isContentActive={emptyFunction}
                         focus={emptyFunction}
-                        styleProvider={() => "rgba(0,0,0,0)"}
+                        styleProvider={() => 'rgba(0,0,0,0)'}
                         docViewPath={returnEmptyDoclist}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
                     />
                 </div>
                 <div className="restart_label" onClick={this.clearUpload}>
@@ -125,28 +141,16 @@ export class AudioUpload extends React.Component {
 
     // Handles the setting of the loading bar
     setOpacity = (index: number, opacity: string) => {
-        const slab = document.getElementById("slab0" + index);
+        const slab = document.getElementById('slab0' + index);
         if (slab) {
             slab.style.opacity = opacity;
         }
-    }
+    };
 
     @observable private dialogueBoxOpacity = 1;
     @observable private overlayOpacity = 0.4;
 
     render() {
-        return (
-            <MainViewModal
-                contents={this.uploadInterface}
-                isDisplayed={true}
-                interactive={true}
-                dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity}
-                overlayDisplayedOpacity={this.overlayOpacity}
-                closeOnExternalClick={this.closeUpload}
-            />
-        );
+        return <MainViewModal contents={this.uploadInterface} isDisplayed={true} interactive={true} dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity} overlayDisplayedOpacity={this.overlayOpacity} closeOnExternalClick={this.closeUpload} />;
     }
-
 }
-
-
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 2ae597b0b..a543c2f70 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -397,7 +397,7 @@ export class MobileInterface extends React.Component {
                     renderDepth={0}
                     isDocumentActive={returnTrue}
                     isContentActive={emptyFunction}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     styleProvider={this.whitebackground}
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
@@ -405,8 +405,6 @@ export class MobileInterface extends React.Component {
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                 />
             </div>
         );
-- 
cgit v1.2.3-70-g09d2


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

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

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

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


From 99326044a2d81a9f0d0312b4d209946e0f119b78 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 24 Apr 2023 17:47:54 -0400
Subject: crappy version of schema image cell preview on hover

---
 .../collections/collectionSchema/SchemaRowBox.tsx  |  2 +-
 .../collectionSchema/SchemaTableCell.tsx           | 65 ++++++++++++++--------
 2 files changed, 43 insertions(+), 24 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 59b571b58..79808d8f8 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -88,7 +88,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return (
             <div
                 className="schema-row"
-                style={{ height: CollectionSchemaView._rowHeight, backgroundColor: this.props.isSelected() ? Colors.LIGHT_BLUE : undefined, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined }}
+                style={{ height: CollectionSchemaView._rowHeight, backgroundColor: this.props.isSelected() ? Colors.LIGHT_BLUE : undefined }}
                 onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 4e31b1e1e..2325339fc 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -58,7 +58,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         };
 
         return (
-            <div className="schemacell-edit-wrapper">
+            <div className="schemacell-edit-wrapper" style={{ cursor: !this.readOnly ? 'text' : 'default', pointerEvents: !this.readOnly && this.props.isRowActive() ? 'all' : 'none' }}>
                 <EditableView
                     contents={<FieldView {...props} />}
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
@@ -76,9 +76,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
 
     getCellWithContent(content: any) {
         return (
-            <div
-                className="schema-table-cell"
-                style={this.props.isRowActive() && !this.readOnly ? { width: this.props.columnWidth, cursor: 'text', pointerEvents: 'auto' } : { width: this.props.columnWidth, cursor: 'default', pointerEvents: 'none' }}>
+            <div className="schema-table-cell" style={this.props.isRowActive() && !this.readOnly ? { width: this.props.columnWidth } : { width: this.props.columnWidth }}>
                 {content}
             </div>
         );
@@ -107,7 +105,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             case ColumnType.Image:
                 return <SchemaImageCell {...this.props} />;
             case ColumnType.Date:
-                return <SchemaDateCell {...this.props} />;
+            // return <SchemaDateCell {...this.props} />;
             default:
                 return this.getCellWithContent(this.defaultCellContent);
         }
@@ -117,16 +115,18 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
 // mj: most of this is adapted from old schema code so I'm not sure what it does tbh
 @observer
 export class SchemaImageCell extends SchemaTableCell {
+    @observable _previewRef: HTMLImageElement | undefined;
+
     choosePath(url: URL) {
         if (url.protocol === 'data') return url.href; // if the url ises the data protocol, just return the href
         if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href); // otherwise, put it through the cors proxy erver
         if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href; //Why is this here — good question
 
         const ext = extname(url.href);
-        return url.href.replace(ext, '_o' + ext);
+        return url.href.replace(ext, '_s' + ext);
     }
 
-    get content() {
+    get url() {
         const field = Cast(this.props.Document[this.props.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc
         const alts = DocListCast(this.props.Document[this.props.fieldKey + '-alternates']); // retrieve alternate documents that may be rendered as alternate images
         const altpaths = alts
@@ -136,13 +136,42 @@ export class SchemaImageCell extends SchemaTableCell {
         const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths;
         // If there is a path, follow it; otherwise, follow a link to a default image icon
         const url = paths.length ? paths : [Utils.CorsProxy('http://www.cs.brown.edu/~bcz/noImage.png')];
+        return url[0];
+    }
+
+    @action
+    showHoverPreview = (e: React.PointerEvent) => {
+        this._previewRef = document.createElement('img');
+        document.body.appendChild(this._previewRef);
+        const ext = extname(this.url);
+        this._previewRef.src = this.url.replace('_s' + ext, '_m' + ext);
+        this._previewRef.style.position = 'absolute';
+        this._previewRef.style.left = e.clientX + 10 + 'px';
+        this._previewRef.style.top = e.clientY + 10 + 'px';
+        this._previewRef.style.zIndex = '1000';
+    };
+
+    @action
+    moveHoverPreview = (e: React.PointerEvent) => {
+        if (!this._previewRef) return;
+        this._previewRef.style.left = e.clientX + 10 + 'px';
+        this._previewRef.style.top = e.clientY + 10 + 'px';
+    };
 
+    @action
+    removeHoverPreview = (e: React.PointerEvent) => {
+        if (!this._previewRef) return;
+        document.body.removeChild(this._previewRef);
+    };
+
+    get content() {
         const aspect = Doc.NativeAspect(this.props.Document); // aspect ratio
-        let width = Math.max(75, this.props.columnWidth); // get a with that is no smaller than 75px
-        const height = Math.max(75, width / aspect); // get a height either proportional to that or 75 px
-        width = height * aspect; // increase the width of the image if necessary to maintain proportionality
+        // let width = Math.max(75, this.props.columnWidth); // get a with that is no smaller than 75px
+        // const height = Math.max(75, width / aspect); // get a height either proportional to that or 75 px
+        const height = CollectionSchemaView._rowHeight - 10;
+        const width = height * aspect; // increase the width of the image if necessary to maintain proportionality
 
-        return <img src={url[0]} width={paths.length ? width : '20px'} height={paths.length ? height : '20px'} />;
+        return <img src={this.url} width={width} height={height} style={{}} draggable="false" onPointerEnter={this.showHoverPreview} onPointerMove={this.moveHoverPreview} onPointerLeave={this.removeHoverPreview} />;
     }
 
     render() {
@@ -171,18 +200,8 @@ export class SchemaDateCell extends SchemaTableCell {
     };
 
     get content() {
-        return !this._pickingDate ? (
-            <div onPointerDown={action(() => (this._pickingDate = true))}>{this.defaultCellContent}</div>
-        ) : (
-            <DatePicker
-                selected={this.date.date}
-                onSelect={(date: any) => {
-                    this.handleChange(date);
-                    this._pickingDate = false;
-                }}
-                onChange={(date: any) => this.handleChange(date)}
-            />
-        );
+        return <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
+        // return !this._pickingDate ? <div onPointerDown={action(() => (this._pickingDate = true))}>{this.defaultCellContent}</div> : <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
     }
 
     render() {
-- 
cgit v1.2.3-70-g09d2


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

---
 .../collectionSchema/CollectionSchemaView.tsx      | 43 ++++++++++++--
 .../collections/collectionSchema/SchemaRowBox.tsx  |  1 +
 .../collectionSchema/SchemaTableCell.tsx           | 65 +++++++++++++---------
 3 files changed, 78 insertions(+), 31 deletions(-)

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

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


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

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

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

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


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

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

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

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


From 08d94147eb855bbb3d7eb964ffa6a7a3248001a2 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 27 Apr 2023 20:41:14 -0400
Subject: forced 'hidden' documents to appear in schema.  added
 colorizing/underlining to schema cells to indicate if value is on layout,
 data, or proto

---
 src/client/views/StyleProvider.tsx                   |  3 ++-
 .../collections/collectionSchema/SchemaTableCell.tsx | 20 +++++++++++++++++++-
 2 files changed, 21 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 5f16e0ebd..c810cb155 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -24,6 +24,7 @@ import { KeyValueBox } from './nodes/KeyValueBox';
 import { SliderBox } from './nodes/SliderBox';
 import './StyleProvider.scss';
 import React = require('react');
+import { SchemaRowBox } from './collections/collectionSchema/SchemaRowBox';
 
 export enum StyleProp {
     TreeViewIcon = 'treeViewIcon',
@@ -173,7 +174,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             if (!backColor) return undefined;
             return lightOrDark(backColor);
         case StyleProp.Hidden:
-            return props?.LayoutTemplateString?.includes(KeyValueBox.name) ? false : BoolCast(doc?.hidden);
+            return props?.LayoutTemplateString?.includes(KeyValueBox.name) || props?.LayoutTemplateString?.includes(SchemaRowBox.name) ? false : BoolCast(doc?.hidden);
         case StyleProp.BorderRounding:
             return StrCast(doc?.[fieldKey + 'borderRounding'], StrCast(doc?.borderRounding, doc?._viewType === CollectionViewType.Pile ? '50%' : ''));
         case StyleProp.TitleHeight:
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 686b21283..bbf8e2bbf 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -90,9 +90,27 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             addDocTab: returnFalse,
             pinToPres: returnZero,
         };
+        let protoCount = 0;
+        let doc: Doc | undefined = this.props.Document;
+        while (doc) {
+            if (Object.keys(doc).includes(this.props.fieldKey)) {
+                break;
+            }
+            protoCount++;
+            doc = doc.proto;
+        }
+        const parenCount = Math.max(0, protoCount - 1);
+        const color = protoCount === 0 ? 'black' : 'blue';
 
         return (
-            <div className="schemacell-edit-wrapper" style={{ cursor: !this.readOnly ? 'text' : 'default', pointerEvents: !this.readOnly && this.props.isRowActive() ? 'all' : 'none' }}>
+            <div
+                className="schemacell-edit-wrapper"
+                style={{
+                    color,
+                    textDecoration: parenCount ? 'underline' : undefined,
+                    cursor: !this.readOnly ? 'text' : 'default',
+                    pointerEvents: !this.readOnly && this.props.isRowActive() ? 'all' : 'none',
+                }}>
                 <EditableView
                     ref={ref => (this._editorRef = ref)}
                     contents={<FieldView {...props} />}
-- 
cgit v1.2.3-70-g09d2


From cc62b9949854f27bc19eb8d4224456094f0dbe13 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 27 Apr 2023 20:48:27 -0400
Subject: from last

---
 src/client/views/collections/collectionSchema/SchemaTableCell.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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

diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index bbf8e2bbf..4f4986b90 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -93,7 +93,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         let protoCount = 0;
         let doc: Doc | undefined = this.props.Document;
         while (doc) {
-            if (Object.keys(doc).includes(this.props.fieldKey)) {
+            if (Object.keys(doc).includes(this.props.fieldKey.replace(/^_/, ''))) {
                 break;
             }
             protoCount++;
-- 
cgit v1.2.3-70-g09d2


From 223dde9f35408c229a4da583083d10cbf81fc264 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 27 Apr 2023 22:23:42 -0400
Subject: fixed some undo issues with schema fill down.  added bool cell view. 
 added UI for showing/setting values on layout vs data docs.

---
 .../collections/collectionSchema/SchemaRowBox.tsx  |   3 +-
 .../collectionSchema/SchemaTableCell.tsx           | 156 ++++++++++++---------
 src/client/views/nodes/KeyValueBox.tsx             |   2 -
 3 files changed, 89 insertions(+), 72 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 9772ce118..ca9e0bda0 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -90,6 +90,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
     deselectCell = () => this.schemaView?.deselectCell();
     selectedCell = () => this.schemaView?._selectedCell;
     setColumnValues = (field: any, value: any) => this.schemaView?.setColumnValues(field, value) ?? false;
+    columnWidth = computedFn((index: number) => () => this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth);
     render() {
         return (
             <div
@@ -131,7 +132,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             Document={this.rootDoc}
                             col={index}
                             fieldKey={key}
-                            columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
+                            columnWidth={this.columnWidth(index)}
                             isRowActive={this.props.isContentActive}
                             getFinfo={this.getFinfo}
                             selectCell={this.selectCell}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 4f4986b90..1fa4312e1 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -5,10 +5,13 @@ import { extname } from 'path';
 import DatePicker from 'react-datepicker';
 import { DateField } from '../../../../fields/DateField';
 import { Doc, DocListCast, Field } from '../../../../fields/Doc';
-import { Cast, DateCast } from '../../../../fields/Types';
+import { BoolCast, Cast, DateCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero, Utils } from '../../../../Utils';
+import { FInfo } from '../../../documents/Documents';
+import { dropActionType } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
+import { undoBatch } from '../../../util/UndoManager';
 import { EditableView } from '../../EditableView';
 import { Colors } from '../../global/globalEnums';
 import { FieldView, FieldViewProps } from '../../nodes/FieldView';
@@ -16,7 +19,6 @@ import { KeyValueBox } from '../../nodes/KeyValueBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
 import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
-import { FInfo } from '../../../documents/Documents';
 
 export interface SchemaTableCellProps {
     Document: Doc;
@@ -25,7 +27,7 @@ export interface SchemaTableCellProps {
     selectCell: (doc: Doc, col: number) => void;
     selectedCell: () => [Doc, number] | undefined;
     fieldKey: string;
-    columnWidth: number;
+    columnWidth: () => number;
     isRowActive: () => boolean | undefined;
     getFinfo: (fieldKey: string) => FInfo | undefined;
     setColumnValues: (field: string, value: string) => boolean;
@@ -33,95 +35,78 @@ export interface SchemaTableCellProps {
 
 @observer
 export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
-    private _editorRef: EditableView | null = null;
-
-    @computed get readOnly() {
-        return this.props.getFinfo(this.props.fieldKey)?.readOnly ?? false;
-    }
-
-    @computed get selected() {
-        const selected: [Doc, number] | undefined = this.props.selectedCell();
-        return this.props.isRowActive() && selected && selected[0] == this.props.Document && selected[1] == this.props.col;
+    public static colRowHeightFunc() {
+        return CollectionSchemaView._rowHeight;
     }
-
-    componentDidUpdate() {
-        if (!this.selected) {
-            this._editorRef?.setIsFocused(false);
-            document.removeEventListener('keydown', this.onKeyDown);
-        } else if (!this.readOnly) {
-            document.addEventListener('keydown', this.onKeyDown);
-        }
-    }
-
-    @action
-    onKeyDown = (e: KeyboardEvent) => {
-        e.stopPropagation();
-        if (e.key == 'Enter') {
-            this._editorRef?.setIsFocused(true);
-        }
-        if (e.key == 'Escape') {
-            this.props.deselectCell();
+    public static renderProps(props: SchemaTableCellProps) {
+        const { Document, fieldKey, getFinfo, columnWidth, isRowActive } = props;
+        let protoCount = 0;
+        let doc: Doc | undefined = Document;
+        while (doc) {
+            if (Object.keys(doc).includes(fieldKey.replace(/^_/, ''))) {
+                break;
+            }
+            protoCount++;
+            doc = doc.proto;
         }
-    };
-    colWidthFunc = () => this.props.columnWidth;
-    colRowHeightFunc = () => CollectionSchemaView._rowHeight;
-    @computed get defaultCellContent() {
-        const props: FieldViewProps = {
-            Document: this.props.Document,
+        const parenCount = Math.max(0, protoCount - 1);
+        const color = protoCount === 0 || (fieldKey.startsWith('_') && Document[fieldKey] === undefined) ? 'black' : 'blue';
+        const textDecoration = color !== 'black' && parenCount ? 'underline' : '';
+        const fieldProps: FieldViewProps = {
             docFilters: returnEmptyFilter,
             docRangeFilters: returnEmptyFilter,
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
             docViewPath: returnEmptyDoclist,
-            fieldKey: this.props.fieldKey,
             rootSelected: returnFalse,
             isSelected: returnFalse,
             setHeight: returnFalse,
             select: emptyFunction,
-            dropAction: 'alias',
+            dropAction: 'alias' as dropActionType,
             bringToFront: emptyFunction,
             renderDepth: 1,
             isContentActive: returnFalse,
             whenChildContentsActiveChanged: emptyFunction,
             ScreenToLocalTransform: Transform.Identity,
             focus: emptyFunction,
-            PanelWidth: this.colWidthFunc,
-            PanelHeight: this.colRowHeightFunc,
             addDocTab: returnFalse,
             pinToPres: returnZero,
+            Document,
+            fieldKey,
+            PanelWidth: columnWidth,
+            PanelHeight: SchemaTableCell.colRowHeightFunc,
         };
-        let protoCount = 0;
-        let doc: Doc | undefined = this.props.Document;
-        while (doc) {
-            if (Object.keys(doc).includes(this.props.fieldKey.replace(/^_/, ''))) {
-                break;
-            }
-            protoCount++;
-            doc = doc.proto;
-        }
-        const parenCount = Math.max(0, protoCount - 1);
-        const color = protoCount === 0 ? 'black' : 'blue';
+        const readOnly = getFinfo(fieldKey)?.readOnly ?? false;
+        const cursor = !readOnly ? 'text' : 'default';
+        const pointerEvents: 'all' | 'none' = !readOnly && isRowActive() ? 'all' : 'none';
+        return { color, textDecoration, fieldProps, cursor, pointerEvents };
+    }
+
+    @computed get selected() {
+        const selected: [Doc, number] | undefined = this.props.selectedCell();
+        return this.props.isRowActive() && selected?.[0] === this.props.Document && selected[1] === this.props.col;
+    }
+
+    @computed get defaultCellContent() {
+        const { color, textDecoration, fieldProps } = SchemaTableCell.renderProps(this.props);
 
         return (
             <div
                 className="schemacell-edit-wrapper"
                 style={{
                     color,
-                    textDecoration: parenCount ? 'underline' : undefined,
-                    cursor: !this.readOnly ? 'text' : 'default',
-                    pointerEvents: !this.readOnly && this.props.isRowActive() ? 'all' : 'none',
+                    textDecoration,
                 }}>
                 <EditableView
-                    ref={ref => (this._editorRef = ref)}
-                    contents={<FieldView {...props} />}
+                    contents={<FieldView {...fieldProps} />}
+                    editing={this.selected ? undefined : false}
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
-                    SetValue={(value: string, shiftDown?: boolean, enterKey?: boolean) => {
+                    SetValue={undoBatch((value: string, shiftDown?: boolean, enterKey?: boolean) => {
                         if (shiftDown && enterKey) {
                             this.props.setColumnValues(this.props.fieldKey, value);
                         }
                         return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
-                    }}
-                    editing={this.selected ? undefined : false}
+                    })}
                 />
             </div>
         );
@@ -146,13 +131,12 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
 
     get content() {
         const cellType: ColumnType = this.getCellType;
+        // prettier-ignore
         switch (cellType) {
-            case ColumnType.Image:
-                return <SchemaImageCell {...this.props} />;
-            case ColumnType.Date:
-            // return <SchemaDateCell {...this.props} />;
-            default:
-                return this.defaultCellContent;
+            case ColumnType.Image: return <SchemaImageCell {...this.props} />;
+            case ColumnType.Boolean: return <SchemaBoolCell {...this.props} />;
+            case ColumnType.Date: // return <SchemaDateCell {...this.props} />;
+            default:  return this.defaultCellContent;
         }
     }
 
@@ -160,10 +144,8 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         return (
             <div
                 className="schema-table-cell"
-                onPointerDown={action(e => {
-                    if (!this.selected) this.props.selectCell(this.props.Document, this.props.col);
-                })}
-                style={{ width: this.props.columnWidth, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
+                onPointerDown={action(e => !this.selected && this.props.selectCell(this.props.Document, this.props.col))}
+                style={{ width: this.props.columnWidth(), border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
                 {this.content}
             </div>
         );
@@ -257,3 +239,39 @@ export class SchemaDateCell extends React.Component<SchemaTableCellProps> {
         return <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
     }
 }
+@observer
+export class SchemaBoolCell extends React.Component<SchemaTableCellProps> {
+    @computed get selected() {
+        const selected: [Doc, number] | undefined = this.props.selectedCell();
+        return this.props.isRowActive() && selected?.[0] === this.props.Document && selected[1] === this.props.col;
+    }
+    render() {
+        const { color, textDecoration, fieldProps, cursor, pointerEvents } = SchemaTableCell.renderProps(this.props);
+        return (
+            <div className="schemaBoolCell" style={{ display: 'flex', color, textDecoration, cursor, pointerEvents }}>
+                <input
+                    style={{ marginRight: 4 }}
+                    type="checkbox"
+                    checked={BoolCast(this.props.Document[this.props.fieldKey])}
+                    onChange={undoBatch((value: React.ChangeEvent<HTMLInputElement> | undefined) => {
+                        if ((value?.nativeEvent as any).shiftKey) {
+                            this.props.setColumnValues(this.props.fieldKey, (color === 'black' ? '=' : '') + value?.target?.checked.toString());
+                        }
+                        KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + value?.target?.checked.toString());
+                    })}
+                />
+                <EditableView
+                    contents={<FieldView {...fieldProps} />}
+                    editing={this.selected ? undefined : false}
+                    GetValue={() => (color === 'black' ? '=' : '') + Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
+                    SetValue={undoBatch((value: string, shiftDown?: boolean, enterKey?: boolean) => {
+                        if (shiftDown && enterKey) {
+                            this.props.setColumnValues(this.props.fieldKey, value);
+                        }
+                        return KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), value);
+                    })}
+                />
+            </div>
+        );
+    }
+}
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 57018fb93..11220c300 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -20,14 +20,12 @@ import { ImageBox } from './ImageBox';
 import './KeyValueBox.scss';
 import { KeyValuePair } from './KeyValuePair';
 import React = require('react');
-import e = require('express');
 
 export type KVPScript = {
     script: CompiledScript;
     type: 'computed' | 'script' | false;
     onDelegate: boolean;
 };
-
 @observer
 export class KeyValueBox extends React.Component<FieldViewProps> {
     public static LayoutString() {
-- 
cgit v1.2.3-70-g09d2


From 773164e71dd6420d5ee669b138f2b6ba05164874 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 27 Apr 2023 22:38:59 -0400
Subject: from last - fix for fill down to write to layout /data doc properly.

---
 src/client/views/collections/collectionSchema/SchemaTableCell.tsx | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 1fa4312e1..003831094 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -103,9 +103,9 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
                     SetValue={undoBatch((value: string, shiftDown?: boolean, enterKey?: boolean) => {
                         if (shiftDown && enterKey) {
-                            this.props.setColumnValues(this.props.fieldKey, value);
+                            this.props.setColumnValues(this.props.fieldKey.replace(/^_/, ''), value);
                         }
-                        return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
+                        return KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), value);
                     })}
                 />
             </div>
@@ -255,7 +255,7 @@ export class SchemaBoolCell extends React.Component<SchemaTableCellProps> {
                     checked={BoolCast(this.props.Document[this.props.fieldKey])}
                     onChange={undoBatch((value: React.ChangeEvent<HTMLInputElement> | undefined) => {
                         if ((value?.nativeEvent as any).shiftKey) {
-                            this.props.setColumnValues(this.props.fieldKey, (color === 'black' ? '=' : '') + value?.target?.checked.toString());
+                            this.props.setColumnValues(this.props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + value?.target?.checked.toString());
                         }
                         KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + value?.target?.checked.toString());
                     })}
@@ -266,7 +266,7 @@ export class SchemaBoolCell extends React.Component<SchemaTableCellProps> {
                     GetValue={() => (color === 'black' ? '=' : '') + Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
                     SetValue={undoBatch((value: string, shiftDown?: boolean, enterKey?: boolean) => {
                         if (shiftDown && enterKey) {
-                            this.props.setColumnValues(this.props.fieldKey, value);
+                            this.props.setColumnValues(this.props.fieldKey.replace(/^_/, ''), value);
                         }
                         return KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), value);
                     })}
-- 
cgit v1.2.3-70-g09d2


From d3dc9938b38e89b2215d13fbc5bc92d33502e818 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 27 Apr 2023 22:53:45 -0400
Subject: one more fix to setting on data/layout for undefined values on '_'
 fields.

---
 src/client/views/collections/collectionSchema/SchemaTableCell.tsx | 2 +-
 src/fields/Doc.ts                                                 | 8 ++++++--
 2 files changed, 7 insertions(+), 3 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 003831094..f17f4a73c 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -263,7 +263,7 @@ export class SchemaBoolCell extends React.Component<SchemaTableCellProps> {
                 <EditableView
                     contents={<FieldView {...fieldProps} />}
                     editing={this.selected ? undefined : false}
-                    GetValue={() => (color === 'black' ? '=' : '') + Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
+                    GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
                     SetValue={undoBatch((value: string, shiftDown?: boolean, enterKey?: boolean) => {
                         if (shiftDown && enterKey) {
                             this.props.setColumnValues(this.props.fieldKey.replace(/^_/, ''), value);
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index b0033b977..22d0664ce 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -29,9 +29,13 @@ import JSZip = require('jszip');
 import * as JSZipUtils from '../JSZipUtils';
 export namespace Field {
     export function toKeyValueString(doc: Doc, key: string): string {
-        const onDelegate = Object.keys(doc).includes(key);
+        const onDelegate = Object.keys(doc).includes(key.replace(/^_/, ''));
         const field = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
-        return !Field.IsField(field) ? '' : (onDelegate ? '=' : '') + (field instanceof ComputedField ? `:=${field.script.originalScript}` : field instanceof ScriptField ? `$=${field.script.originalScript}` : Field.toScriptString(field));
+        return !Field.IsField(field)
+            ? key.startsWith('_')
+                ? '='
+                : ''
+            : (onDelegate ? '=' : '') + (field instanceof ComputedField ? `:=${field.script.originalScript}` : field instanceof ScriptField ? `$=${field.script.originalScript}` : Field.toScriptString(field));
     }
     export function toScriptString(field: Field): string {
         switch (typeof field) {
-- 
cgit v1.2.3-70-g09d2


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

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

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

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

