diff options
| -rw-r--r-- | package-lock.json | 208 | ||||
| -rw-r--r-- | package.json | 4 | ||||
| -rw-r--r-- | src/client/documents/Documents.ts | 45 | ||||
| -rw-r--r-- | src/client/views/EditableView.tsx | 6 | ||||
| -rw-r--r-- | src/client/views/StyleProvider.tsx | 1 | ||||
| -rw-r--r-- | src/client/views/collections/collectionLinear/CollectionLinearView.tsx | 20 | ||||
| -rw-r--r-- | src/client/views/collections/collectionSchema/CollectionSchemaView.scss | 17 | ||||
| -rw-r--r-- | src/client/views/collections/collectionSchema/CollectionSchemaView.tsx | 331 | ||||
| -rw-r--r-- | src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx | 27 | ||||
| -rw-r--r-- | src/client/views/collections/collectionSchema/SchemaRowBox.tsx | 22 | ||||
| -rw-r--r-- | src/client/views/collections/collectionSchema/SchemaTableCell.tsx | 260 | ||||
| -rw-r--r-- | src/client/views/nodes/KeyValueBox.tsx | 2 | ||||
| -rw-r--r-- | src/fields/Doc.ts | 8 |
13 files changed, 661 insertions, 290 deletions
diff --git a/package-lock.json b/package-lock.json index a8f5476ea..7d2ef9509 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2452,7 +2452,7 @@ "@types/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=", + "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", "dev": true }, "@types/strip-json-comments": { @@ -2803,7 +2803,7 @@ "textarea-caret": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/textarea-caret/-/textarea-caret-3.0.2.tgz", - "integrity": "sha512-gRzeti2YS4did7UJnPQ47wrjD+vp+CJIe9zbsu0bJ987d8QVLvLNG9757rqiQTIy4hGIeFauTTJt5Xkn51UkXg==" + "integrity": "sha1-82DEhpmqGr9xhoCkOjGoUGZcLK8=" } } }, @@ -2902,7 +2902,7 @@ "after": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==" + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" }, "agent-base": { "version": "6.0.2", @@ -3799,7 +3799,7 @@ "backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==" + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" }, "bail": { "version": "2.0.2", @@ -3869,7 +3869,7 @@ "base64-arraybuffer": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", - "integrity": "sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==" + "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=" }, "base64-js": { "version": "1.5.1", @@ -4842,7 +4842,7 @@ "component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", - "integrity": "sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw==" + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" }, "component-emitter": { "version": "1.3.0", @@ -4852,7 +4852,7 @@ "component-inherit": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", - "integrity": "sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA==" + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" }, "compress-commons": { "version": "2.1.1", @@ -5572,7 +5572,7 @@ "custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==" + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=" }, "cyclist": { "version": "1.0.1", @@ -6656,7 +6656,7 @@ "dynamic-dedupe": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", - "integrity": "sha1-BuRMIj9eTpTXjvnbI6ZRXOL5YqE=", + "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", "dev": true, "requires": { "xtend": "^4.0.0" @@ -6786,7 +6786,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "ws": { "version": "7.4.6", @@ -9316,7 +9316,7 @@ "fs-extra": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", - "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", + "integrity": "sha512-waKu+1KumRhYv8D8gMRCKJGAMI9pRnPuEb1mvgYD0f7wBscg+h6bW4FDTmEZhB9VKxvoTtxW+Y7bnIlB7zja6Q==", "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^2.1.0", @@ -9976,14 +9976,14 @@ "isarray": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==" + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" } } }, "has-cors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==" + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" }, "has-flag": { "version": "3.0.0", @@ -10559,7 +10559,7 @@ "indexof": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==" + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" }, "inflight": { "version": "1.0.6", @@ -11670,7 +11670,7 @@ "jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", "requires": { "graceful-fs": "^4.1.6" } @@ -12093,7 +12093,7 @@ "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" }, "lodash.isplainobject": { "version": "4.0.6", @@ -12354,7 +12354,7 @@ "mathquill": { "version": "0.10.1-a", "resolved": "https://registry.npmjs.org/mathquill/-/mathquill-0.10.1-a.tgz", - "integrity": "sha512-snSAEwAtwdwBFSor+nVBnWWQtTw67kgAgKMyAIxuz4ZPboy0qkWZmd7BL3lfOXp/INihhRlU1PcfaAtDaRhmzA==", + "integrity": "sha1-vyylaQEAY6w0vNXVKa3Ag3zVPD8=", "requires": { "jquery": "^1.12.3" }, @@ -12362,7 +12362,7 @@ "jquery": { "version": "1.12.4", "resolved": "https://registry.npmjs.org/jquery/-/jquery-1.12.4.tgz", - "integrity": "sha512-UEVp7PPK9xXYSk8xqXCJrkXnKZtlgWkd2GsAQbMRFK6S/ePU2JN5G2Zum8hIVjzR3CpdfSqdqAzId/xd4TJHeg==" + "integrity": "sha1-AeHfuikP5z3rp3zurLD5ui/sngw=" } } }, @@ -14048,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", @@ -14151,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==" } } @@ -14166,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==" } } @@ -14175,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" @@ -14188,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": { @@ -14198,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" @@ -14234,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": { @@ -14282,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", @@ -14319,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": { @@ -14463,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" @@ -14471,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": { @@ -14501,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==" } } @@ -14516,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==" } } @@ -14525,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", @@ -14626,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" @@ -14659,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": { @@ -14705,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", @@ -14757,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==" } } @@ -14772,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==" } } @@ -14781,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", @@ -14816,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": { @@ -14900,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": { @@ -14910,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": { @@ -14948,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==" } } @@ -14963,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==" } } @@ -14972,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", @@ -15010,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==" } } @@ -15025,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==" } } @@ -15093,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==" } } @@ -15108,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==" } } @@ -15117,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": { @@ -15207,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" @@ -15215,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", @@ -15228,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" @@ -15271,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": { @@ -15355,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", @@ -15482,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" @@ -15561,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": { @@ -15576,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": { @@ -15591,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": { @@ -15601,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": { @@ -15819,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", @@ -15948,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": { @@ -15966,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" @@ -16015,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" @@ -16063,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", @@ -16401,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==" } } @@ -16416,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==" } } @@ -16430,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": { @@ -16450,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": { @@ -16499,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": { @@ -16522,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": { @@ -16562,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", @@ -16578,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": { @@ -16624,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", @@ -16683,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", @@ -16753,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": { @@ -16924,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", @@ -16980,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==" } } @@ -16995,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==" } } @@ -17009,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": { @@ -17165,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==" } } @@ -17180,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==" } } @@ -17199,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", @@ -17208,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==" } } @@ -17223,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": { @@ -17294,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" @@ -17335,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": { @@ -17357,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", @@ -17865,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" @@ -22168,7 +22168,7 @@ "to-array": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", - "integrity": "sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A==" + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" }, "to-fast-properties": { "version": "2.0.0", @@ -22540,7 +22540,7 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true } } @@ -23797,7 +23797,7 @@ "resolve-cwd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "integrity": "sha512-ccu8zQTrzVr954472aUVPLEcB3YpKSYR3cg/3lo1okzobPBM+1INXBbBZlDbnI/hbEocnf8j0QVo43hQKrbchg==", "dev": true, "requires": { "resolve-from": "^3.0.0" @@ -23806,7 +23806,7 @@ "resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", "dev": true }, "semver": { @@ -24358,7 +24358,7 @@ "yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==" + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" }, "yn": { "version": "3.1.1", diff --git a/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 dee5feebc..b81ca6b2b 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -68,14 +68,16 @@ class EmptyBox { return ''; } } -export abstract class FInfo { +export class FInfo { description: string = ''; - fieldType?: 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 { @@ -85,16 +87,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; } } @@ -102,21 +104,28 @@ 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; +} +class DateInfo extends FInfo { + fieldType? = 'date'; + values?: DateField[] = []; } type BOOLt = BoolInfo | boolean; type NUMt = NumInfo | number; @@ -125,15 +134,17 @@ type DOCt = DocInfo | Doc; type DIMt = DimInfo | typeof DimUnit.Pixel | typeof DimUnit.Ratio; type PEVt = PEInfo | 'none' | 'all'; type DROPt = DAInfo | dropActionType; +type DATEt = DateInfo | number; export class DocumentOptions { x?: NUMt = new NumInfo('x coordinate of document in a freeform view'); y?: NUMt = new NumInfo('y coordinage of document in a freeform view'); - 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; + creationDate?: DATEt = new DateInfo('date the document was created', true); _dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else"); - allowOverlayDrop?: BOOLt = new BoolInfo('can documents be dropped onto this document without using dragging title bar or holding down embed key (ctrl)?'); + 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)'); @@ -199,11 +210,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/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/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index d98e5aa80..d13052f71 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', 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.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 1ef2fb4ef..a9434fde3 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -9,13 +9,18 @@ .schema-table { background-color: $white; cursor: grab; - overflow: scroll; + + .schema-table-content { + overflow: overlay; + scroll-behavior: smooth; + } .schema-column-menu, .schema-filter-menu { background: $light-gray; position: absolute; min-width: 200px; + max-width: 400px; display: flex; flex-direction: column; align-items: flex-start; @@ -26,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 6d5a73e55..3dff8d769 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1,21 +1,22 @@ import React = require('react'); import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable, ObservableMap, untracked } from 'mobx'; +import { action, computed, observable, ObservableMap, observe, trace } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; -import { Doc, 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'; 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'; import { undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { EditableView } from '../../EditableView'; +import { Colors } from '../../global/globalEnums'; import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { KeyValueBox } from '../../nodes/KeyValueBox'; @@ -29,52 +30,57 @@ export enum ColumnType { Number, String, Boolean, - Doc, + 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 export class CollectionSchemaView extends CollectionSubView() { + private _keysDisposer: any; private _closestDropIndex: number = 0; private _previewRef: HTMLDivElement | null = null; private _makeNewColumn: boolean = false; + private _documentOptions: DocumentOptions = new DocumentOptions(); + private _tableContentRef: HTMLDivElement | null = null; - 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; + 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 _menuOptions: string[] = []; @observable _newFieldWarning: string = ''; @observable _makeNewField: boolean = false; @observable _newFieldDefault: any = 0; @observable _newFieldType: ColumnType = ColumnType.Number; @observable _menuValue: string = ''; @observable _filterColumnIndex: number | undefined; - @observable _filterValue: string = ''; - - get documentKeys() { - const docs = this.childDocs; - const keys: { [key: string]: boolean } = {}; - // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields. - // then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be - // invalidated and re-rendered. This workaround will inquire all of the document fields before the options button is clicked. - // then by the time the options button is clicked, all of the fields should be in place. If a new field is added while this menu - // is displayed (unlikely) it won't show up until something else changes. - //TODO Types - untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false))))); - - // this.columns.forEach(key => (keys[key.heading] = true)); - return Array.from(Object.keys(keys)); + @observable _filterSearchValue: string = ''; + @observable _selectedCell: [Doc, number] | undefined; + + @computed get _selectedDocs() { + return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.context), this.rootDoc)); + } + + @computed get documentKeys() { + return Array.from(this.fieldInfos.keys()); } @computed get previewWidth() { @@ -90,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; } @@ -119,19 +120,37 @@ export class CollectionSchemaView extends CollectionSubView() { return BoolCast(this.layoutDoc.sortDesc); } - rowIndex(doc: Doc) { - return this.childDocs.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.value as Doc).forEach(action(key => // check if any of its keys are new, and add them + !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo('')))))); + break; + case 'update': //let oldValue = change.oldValue; // fill this in if the entire child list will ever be reassigned with a new list + } + }, + 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) { @@ -140,30 +159,62 @@ export class CollectionSchemaView extends CollectionSubView() { { const lastDoc = this._selectedDocs.lastElement(); const lastIndex = this.rowIndex(lastDoc); - const curDoc = this.childDocs[lastIndex]; + const curDoc = this.sortedDocs.docs[lastIndex]; if (lastIndex >= 0 && lastIndex < this.childDocs.length - 1) { !e.shiftKey && this.clearSelection(); - const newDoc = this.childDocs[lastIndex + 1]; - if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc)); - else this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1); + const newDoc = this.sortedDocs.docs[lastIndex + 1]; + if (this._selectedDocs.includes(newDoc)) { + SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc)); + } else { + this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1); + this._selectedCell && (this._selectedCell[0] = newDoc); + this.scrollToDoc(newDoc, {}); + } } e.stopPropagation(); + e.preventDefault(); } break; case 'ArrowUp': { const firstDoc = this._selectedDocs.lastElement(); const firstIndex = this.rowIndex(firstDoc); - const curDoc = this.childDocs[firstIndex]; + const curDoc = this.sortedDocs.docs[firstIndex]; if (firstIndex > 0 && firstIndex < this.childDocs.length) { !e.shiftKey && this.clearSelection(); - const newDoc = this.childDocs[firstIndex - 1]; + const newDoc = this.sortedDocs.docs[firstIndex - 1]; if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc)); - else this.addDocToSelection(newDoc, e.shiftKey, firstIndex - 1); + 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.deselectCell(); + } } } }; @@ -177,7 +228,6 @@ export class CollectionSchemaView extends CollectionSubView() { addRow = (doc: Doc | Doc[]) => { const result: boolean = this.addDocument(doc); - this.setSort(this.sortField, this.sortDesc); return result; }; @@ -270,18 +320,13 @@ export class CollectionSchemaView extends CollectionSubView() { @undoBatch @action - swapColumns = (index1: number, index2: number) => { - const tempKey = this.columnKeys[index1]; - const tempWidth = this.storedColumnWidths[index1]; - - let currKeys = this.columnKeys; - currKeys[index1] = currKeys[index2]; - currKeys[index2] = tempKey; + moveColumn = (fromIndex: number, toIndex: number) => { + let currKeys = this.columnKeys.slice(); + currKeys.splice(toIndex, 0, currKeys.splice(fromIndex, 1)[0]); this.layoutDoc.columnKeys = new List<string>(currKeys); - let currWidths = this.storedColumnWidths; - currWidths[index1] = currWidths[index2]; - currWidths[index2] = tempWidth; + let currWidths = this.storedColumnWidths.slice(); + currWidths.splice(toIndex, 0, currWidths.splice(fromIndex, 1)[0]); this.layoutDoc.columnWidths = new List<number>(currWidths); }; @@ -294,10 +339,45 @@ export class CollectionSchemaView extends CollectionSubView() { }); DragManager.StartColumnDrag(dragEles, dragData, e.x, e.y); + document.removeEventListener('pointermove', this.highlightDropColumn); + document.addEventListener('pointermove', this.highlightDropColumn); + let stopHighlight = (e: PointerEvent) => { + document.removeEventListener('pointermove', this.highlightDropColumn); + document.removeEventListener('pointerup', stopHighlight); + }; + document.addEventListener('pointerup', stopHighlight); + return true; }; @action + highlightDropColumn = (e: PointerEvent) => { + e.stopPropagation(); + const mouseX = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0]; + let index: number | undefined; + this.displayColumnWidths.reduce((total, curr, i) => { + if (total <= mouseX && total + curr >= mouseX) { + if (mouseX <= total + curr / 2) index = i; + else index = i + 1; + } + return total + curr; + }, CollectionSchemaView._rowMenuWidth); + + this._colEles.forEach((colRef, i) => { + let leftStyle = ''; + let rightStyle = ''; + if (i + 1 === index) rightStyle = `solid 2px ${Colors.MEDIUM_BLUE}`; + if (i === index && i === 0) leftStyle = `solid 2px ${Colors.MEDIUM_BLUE}`; + colRef.style.borderLeft = leftStyle; + colRef.style.borderRight = rightStyle; + this.childDocs.forEach(doc => { + this._rowEles.get(doc).children[1].children[i].style.borderLeft = leftStyle; + this._rowEles.get(doc).children[1].children[i].style.borderRight = rightStyle; + }); + }); + }; + + @action addRowRef = (doc: Doc, ref: HTMLDivElement) => this._rowEles.set(doc, ref); @action @@ -319,17 +399,27 @@ export class CollectionSchemaView extends CollectionSubView() { clearSelection = () => SelectionManager.DeselectAll(); selectRows = (rootDoc: Doc, lastSelected: Doc) => { - const index = this.childDocs.indexOf(rootDoc); - const lastSelectedRow = this.childDocs.indexOf(lastSelected); + const index = this.rowIndex(rootDoc); + const lastSelectedRow = this.rowIndex(lastSelected); const startRow = Math.min(lastSelectedRow, index); const endRow = Math.max(lastSelectedRow, index); for (let i = startRow; i <= endRow; i++) { - const currDoc = this.childDocs[i]; + const currDoc = this.sortedDocs.docs[i]; if (!this._selectedDocs.includes(currDoc)) this.addDocToSelection(currDoc, true, i); } }; - sortedSelectedDocs = () => this.childDocs.filter(doc => this._selectedDocs.includes(doc)); + @action + selectCell = (doc: Doc, index: number) => { + 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); @@ -338,25 +428,34 @@ export class CollectionSchemaView extends CollectionSubView() { if (de.complete.columnDragData) { e.stopPropagation(); const mouseX = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y)[0]; - let i = de.complete.columnDragData.colIndex; - this.displayColumnWidths.reduce((total, curr, index) => { + let index = de.complete.columnDragData.colIndex; + this.displayColumnWidths.reduce((total, curr, i) => { if (total <= mouseX && total + curr >= mouseX) { - i = index; + if (mouseX <= total + curr / 2) index = i; + else index = i + 1; } return total + curr; }, CollectionSchemaView._rowMenuWidth); - this.swapColumns(de.complete.columnDragData.colIndex, i); - e.stopPropagation(); + this.moveColumn(de.complete.columnDragData.colIndex, index); + + this._colEles.forEach((colRef, i) => { + colRef.style.borderLeft = ''; + colRef.style.borderRight = ''; + this.childDocs.forEach(doc => { + this._rowEles.get(doc).children[1].children[i].style.borderLeft = ''; + this._rowEles.get(doc).children[1].children[i].style.borderRight = ''; + }); + }); + return true; } const draggedDocs = de.complete.docDragData?.draggedDocuments; - 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)); this.dataDoc[this.fieldKey ?? 'data'] = new List<Doc>([...removed, ...draggedDocs, ...pushedDocs]); - this.setSort(undefined); - SelectionManager.DeselectAll(); + this.clearSelection(); draggedDocs.forEach(doc => { const draggedView = DocumentManager.Instance.getFirstDocumentView(doc); if (draggedView) DocumentManager.Instance.RemoveView(draggedView); @@ -371,7 +470,6 @@ export class CollectionSchemaView extends CollectionSubView() { @action onExternalDrop = async (e: React.DragEvent): Promise<void> => { super.onExternalDrop(e, {}, undoBatch(action(docus => docus.map((doc: Doc) => this.addDocument(doc))))); - this.setSort(undefined); }; onDividerDown = (e: React.PointerEvent) => setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, emptyFunction); @@ -410,18 +508,21 @@ export class CollectionSchemaView extends CollectionSubView() { focusDocument = (doc: Doc, options: DocFocusOptions) => { Doc.BrushDoc(doc); + this.scrollToDoc(doc, options); + return undefined; + }; - const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); + scrollToDoc = (doc: Doc, options: DocFocusOptions) => { + const found = this._tableContentRef && Array.from(this._tableContentRef.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); if (found) { - const top = found.getBoundingClientRect().top; - const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top); - if (Math.floor(localTop[1]) !== 0) { - let focusSpeed = options.zoomTime ?? 500; - smoothScroll(focusSpeed, this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc); + const rect = found.getBoundingClientRect(); + const localRect = this.props.ScreenToLocalTransform().transformBounds(rect.left, rect.top, rect.width, rect.height); + if (localRect.y < CollectionSchemaView._rowHeight || localRect.y + localRect.height > this.props.PanelHeight()) { + let focusSpeed = options.zoomTime ?? 50; + smoothScroll(focusSpeed, this._tableContentRef!, localRect.y + this._tableContentRef!.scrollTop - CollectionSchemaView._rowHeight, options.easeFunc); return focusSpeed; } } - return undefined; }; @computed get fieldDefaultInput() { @@ -443,7 +544,7 @@ 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))(); + this._menuKeys.length > 0 && this._menuValue.length > 0 ? this.setKey(this._menuKeys[0]) : action(() => (this._makeNewField = true))(); break; case 'Escape': this.closeColumnMenu(); @@ -472,7 +573,7 @@ export class CollectionSchemaView extends CollectionSubView() { this._makeNewColumn = false; this._columnMenuIndex = index; this._menuValue = ''; - this._menuOptions = this.documentKeys; + this._menuKeys = this.documentKeys; this._makeNewField = false; this._newFieldWarning = ''; this._makeNewField = false; @@ -485,24 +586,17 @@ export class CollectionSchemaView extends CollectionSubView() { @action openFilterMenu = (index: number) => { this._filterColumnIndex = index; - this._filterValue = this.getFieldFilters(this.columnKeys[this._filterColumnIndex!]).map(filter => filter.split(':')[1])[0]; + this._filterSearchValue = ''; }; @action - closeFilterMenu = (setValue: boolean) => { - if (setValue) { - if (this._filterValue !== '') { - Doc.setDocFilter(this.Document, this.columnKeys[this._filterColumnIndex!], this._filterValue, 'check', false, undefined, false); - } else { - this.removeFieldFilters(this.columnKeys[this._filterColumnIndex!]); - } - } + closeFilterMenu = () => { this._filterColumnIndex = undefined; }; openContextMenu = (x: number, y: number, index: number) => { this.closeColumnMenu(); - this.closeFilterMenu(false); + this.closeFilterMenu(); ContextMenu.Instance.clearItems(); ContextMenu.Instance.addItem({ description: 'Change field', @@ -525,7 +619,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._menuKeys = this.documentKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase())); }; getFieldFilters = (field: string) => StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field); @@ -535,15 +629,16 @@ export class CollectionSchemaView extends CollectionSubView() { }; onFilterKeyDown = (e: React.KeyboardEvent) => { - //prettier-ignore switch (e.key) { - case 'Enter' : this.closeFilterMenu(true); break; - case 'Escape': this.closeFilterMenu(false);break; + case 'Enter': + case 'Escape': + this.closeFilterMenu(); + break; } }; @action - updateFilterSearch = (e: React.ChangeEvent<HTMLInputElement>) => (this._filterValue = e.target.value); + updateFilterSearch = (e: React.ChangeEvent<HTMLInputElement>) => (this._filterSearchValue = e.target.value); @computed get newFieldMenu() { return ( @@ -626,14 +721,23 @@ export class CollectionSchemaView extends CollectionSubView() { { passive: false } ) }> - {this._menuOptions.map(key => ( + {this._menuKeys.map(key => ( <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} + {this.fieldInfos.get(key)!.fieldType ? ', ' : ''} + </span> + <span className="schema-search-result-type" style={{ color: this.fieldInfos.get(key)!.readOnly ? 'red' : 'inherit' }}> + {this.fieldInfos.get(key)!.fieldType} + </span> + </p> + <p className="schema-search-result-desc">{this.fieldInfos.get(key)!.description}</p> </div> ))} </div> @@ -662,21 +766,16 @@ export class CollectionSchemaView extends CollectionSubView() { @computed get renderFilterOptions() { const keyOptions: string[] = []; const columnKey = this.columnKeys[this._filterColumnIndex!]; - this.childDocs.forEach(doc => { - const key = StrCast(doc[columnKey]); - if (keyOptions.includes(key) === false && (key.includes(this._filterValue) || !this._filterValue) && key !== '') { - keyOptions.push(key); + const allDocs = DocListCast(this.dataDoc[this.props.fieldKey]); + allDocs.forEach(doc => { + const value = StrCast(doc[columnKey]); + if (!keyOptions.includes(value) && value !== '' && (this._filterSearchValue === '' || value.includes(this._filterSearchValue))) { + keyOptions.push(value); } }); const filters = StrListCast(this.Document._docFilters); - for (let i = 0; i < (filters?.length ?? 0) - 1; i++) { - if (filters[i] === columnKey && keyOptions.includes(filters[i].split(':')[1]) === false) { - keyOptions.push(filters[i + 1]); - } - } - - const options = keyOptions.map(key => { + return keyOptions.map(key => { let bool = false; if (filters !== undefined) { const ind = filters.findIndex(filter => filter.split(':')[1] === key); @@ -702,21 +801,19 @@ export class CollectionSchemaView extends CollectionSubView() { </div> ); }); - - return options; } @computed get renderFilterMenu() { const x = this.displayColumnWidths.reduce((total, curr, index) => total + (index < this._filterColumnIndex! ? curr : 0), CollectionSchemaView._rowMenuWidth); return ( <div className="schema-filter-menu" style={{ left: x, minWidth: CollectionSchemaView._minColWidth }}> - <input className="schema-filter-input" type="text" value={this._filterValue} onKeyDown={this.onFilterKeyDown} onChange={this.updateFilterSearch} onPointerDown={e => e.stopPropagation()} /> + <input className="schema-filter-input" type="text" value={this._filterSearchValue} onKeyDown={this.onFilterKeyDown} onChange={this.updateFilterSearch} onPointerDown={e => e.stopPropagation()} /> {this.renderFilterOptions} <div className="schema-column-menu-button" onPointerDown={action(e => { e.stopPropagation(); - this.closeFilterMenu(true); + this.closeFilterMenu(); })}> done </div> @@ -725,11 +822,12 @@ export class CollectionSchemaView extends CollectionSubView() { } @computed get sortedDocs() { + trace(); const field = StrCast(this.layoutDoc.sortField); const desc = BoolCast(this.layoutDoc.sortDesc); const docs = !field ? this.childDocs - : this.childDocs.sort((docA, docB) => { + : [...this.childDocs].sort((docA, docB) => { const aStr = Field.toString(docA[field] as Field); const bStr = Field.toString(docB[field] as Field); var out = 0; @@ -779,9 +877,8 @@ export class CollectionSchemaView extends CollectionSubView() { </div> {this._columnMenuIndex !== undefined && this.renderColumnMenu} {this._filterColumnIndex !== undefined && this.renderFilterMenu} - <CollectionSchemaViewDocs schema={this} childDocs={this.sortedDocsFunc} /> - - <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} /> + <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>} {this.previewWidth > 0 && ( @@ -809,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} @@ -824,6 +921,7 @@ export class CollectionSchemaView extends CollectionSubView() { interface CollectionSchemaViewDocsProps { schema: CollectionSchemaView; + setRef: (ref: HTMLDivElement | null) => void; childDocs: () => { docs: Doc[] }; } @@ -834,11 +932,11 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP childScreenToLocal = computedFn((index: number) => () => this.props.schema.props.ScreenToLocalTransform().translate(0, -CollectionSchemaView._rowHeight - index * this.rowHeightFunc())); render() { return ( - <div className="schema-table-content"> + <div className="schema-table-content" ref={this.props.setRef} style={{ height: `calc(100% - ${CollectionSchemaView._newNodeInputHeight + CollectionSchemaView._rowHeight}px)` }}> {this.props.childDocs().docs.map((doc: Doc, index: number) => { const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField ? undefined : this.props.schema.props.DataDoc; return ( - <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} @@ -863,13 +961,14 @@ 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} hideLinkAnchors={true} fitWidth={returnTrue} scriptContext={this} + canEmbedOnDrag={true} /> </div> ); diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index d88d67c94..243fe0c61 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -1,10 +1,12 @@ import React = require('react'); import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed } from 'mobx'; +import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import { emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import { Colors } from '../../global/globalEnums'; import './CollectionSchemaView.scss'; +import { SnappingManager } from '../../../util/SnappingManager'; +import { DragManager } from '../../../util/DragManager'; export interface SchemaColumnHeaderProps { columnKeys: string[]; @@ -12,7 +14,7 @@ export interface SchemaColumnHeaderProps { columnIndex: number; sortField: string; sortDesc: boolean; - setSort: (field: string, desc: boolean) => void; + setSort: (field: string | undefined, desc?: boolean) => void; removeColumn: (index: number) => void; resizeColumn: (e: any, index: number) => void; dragColumn: (e: any, index: number) => boolean; @@ -22,6 +24,8 @@ export interface SchemaColumnHeaderProps { @observer export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps> { + @observable _ref: HTMLDivElement | null = null; + @computed get fieldKey() { return this.props.columnKeys[this.props.columnIndex]; } @@ -30,8 +34,10 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps> sortClicked = (e: React.PointerEvent) => { e.stopPropagation(); e.preventDefault(); - if (this.props.sortField == this.fieldKey) { - this.props.setSort(this.fieldKey, !this.props.sortDesc); + if (this.props.sortField == this.fieldKey && this.props.sortDesc) { + this.props.setSort(undefined); + } else if (this.props.sortField == this.fieldKey) { + this.props.setSort(this.fieldKey, true); } else { this.props.setSort(this.fieldKey, false); } @@ -44,7 +50,18 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps> render() { return ( - <div className="schema-column-header" style={{ width: this.props.columnWidths[this.props.columnIndex] }} onPointerDown={this.onPointerDown} ref={col => col && this.props.setColRef(this.props.columnIndex, col)}> + <div + className="schema-column-header" + style={{ + width: this.props.columnWidths[this.props.columnIndex], + }} + onPointerDown={this.onPointerDown} + ref={col => { + if (col) { + this._ref = col; + this.props.setColRef(this.props.columnIndex, col); + } + }}> <div className="schema-column-resizer left" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex)}></div> <div className="schema-column-title">{this.fieldKey}</div> diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 856537927..ca9e0bda0 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,8 +26,7 @@ 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; } @computed get schemaDoc() { @@ -84,11 +85,17 @@ 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; + columnWidth = computedFn((index: number) => () => this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth); render() { 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) => { @@ -123,10 +130,15 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() { <SchemaTableCell key={key} Document={this.rootDoc} + col={index} fieldKey={key} - columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth} + columnWidth={this.columnWidth(index)} 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 5f8ffe8b0..f17f4a73c 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -1,66 +1,276 @@ import React = require('react'); +import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; -import { Doc, Field } from '../../../../fields/Doc'; -import { 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 { 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'; import { KeyValueBox } from '../../nodes/KeyValueBox'; import { DefaultStyleProvider } from '../../StyleProvider'; -import { CollectionSchemaView } from './CollectionSchemaView'; +import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSchemaView'; import './CollectionSchemaView.scss'; export interface SchemaTableCellProps { Document: Doc; + col: number; + deselectCell: () => void; + 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; } @observer export class SchemaTableCell extends React.Component<SchemaTableCellProps> { - render() { - const props: FieldViewProps = { - Document: this.props.Document, + public static colRowHeightFunc() { + return CollectionSchemaView._rowHeight; + } + 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; + } + 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.props.columnWidth, - PanelHeight: () => CollectionSchemaView._rowHeight, addDocTab: returnFalse, pinToPres: returnZero, + Document, + fieldKey, + PanelWidth: columnWidth, + PanelHeight: SchemaTableCell.colRowHeightFunc, }; + 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, + }}> + <EditableView + contents={<FieldView {...fieldProps} />} + editing={this.selected ? undefined : false} + 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); + } + return KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), value); + })} + /> + </div> + ); + } + + 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; + + return ColumnType.Any; + } + + get content() { + const cellType: ColumnType = this.getCellType; + // prettier-ignore + switch (cellType) { + 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; + } + } + + render() { + return ( + <div + className="schema-table-cell" + 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> + ); + } +} + +// mj: most of this is adapted from old schema code so I'm not sure what it does tbh +@observer +export class SchemaImageCell extends React.Component<SchemaTableCellProps> { + @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, '_s' + ext); + } + + 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 + .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')]; + 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); + }; + + 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 + const height = CollectionSchemaView._rowHeight - 10; + const width = height * aspect; // increase the width of the image if necessary to maintain proportionality + + return <img src={this.url} width={width} height={height} style={{}} draggable="false" onPointerEnter={this.showHoverPreview} onPointerMove={this.moveHoverPreview} onPointerLeave={this.removeHoverPreview} />; + } +} + +@observer +export class SchemaDateCell extends React.Component<SchemaTableCellProps> { + @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); + //} + }; + + render() { + 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="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' }}> - <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="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.replace(/^_/, ''), (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={() => 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); + } + 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 2f5760699..b54364332 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() { diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 0c2ee35fd..93c28cf08 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) { |
