From 7934c38ed641f4a10cd008fe415a50aef1240e10 Mon Sep 17 00:00:00 2001 From: mehekj Date: Mon, 3 Apr 2023 17:28:51 -0400 Subject: fixed dragging doc out of schema and removing schema column sort --- .../views/collections/collectionSchema/CollectionSchemaView.tsx | 6 ++---- .../views/collections/collectionSchema/SchemaColumnHeader.tsx | 8 +++++--- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index d47c9762c..967e10434 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -180,7 +180,6 @@ export class CollectionSchemaView extends CollectionSubView() { addRow = (doc: Doc | Doc[]) => { const result: boolean = this.addDocument(doc); - this.setSort(this.sortField, this.sortDesc); return result; }; @@ -362,7 +361,6 @@ export class CollectionSchemaView extends CollectionSubView() { const pushedAndDraggedDocs = [...pushedDocs, ...draggedDocs]; const removed = this.childDocs.slice().filter(doc => !pushedAndDraggedDocs.includes(doc)); this.dataDoc[this.fieldKey ?? 'data'] = new List([...removed, ...draggedDocs, ...pushedDocs]); - this.setSort(undefined); SelectionManager.DeselectAll(); draggedDocs.forEach(doc => { const draggedView = DocumentManager.Instance.getFirstDocumentView(doc); @@ -378,7 +376,6 @@ export class CollectionSchemaView extends CollectionSubView() { @action onExternalDrop = async (e: React.DragEvent): Promise => { super.onExternalDrop(e, {}, undoBatch(action(docus => docus.map((doc: Doc) => this.addDocument(doc))))); - this.setSort(undefined); }; onDividerDown = (e: React.PointerEvent) => setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, emptyFunction); @@ -799,7 +796,7 @@ export class CollectionSchemaView extends CollectionSubView() { const desc = BoolCast(this.layoutDoc.sortDesc); const docs = !field ? this.childDocs - : this.childDocs.sort((docA, docB) => { + : [...this.childDocs].sort((docA, docB) => { const aStr = Field.toString(docA[field] as Field); const bStr = Field.toString(docB[field] as Field); var out = 0; @@ -943,6 +940,7 @@ class CollectionSchemaViewDocs extends React.Component ); diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index cbdaeb933..43895fc9c 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -12,7 +12,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; @@ -30,8 +30,10 @@ export class SchemaColumnHeader extends React.Component 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); } -- cgit v1.2.3-70-g09d2 From 96de14ba8ee055c3d18540fa54b979c27c2f6f13 Mon Sep 17 00:00:00 2001 From: mehekj Date: Mon, 10 Apr 2023 17:49:25 -0400 Subject: fixed schema table scroll bar css --- package-lock.json | 131 ++++++++++++++++----- .../collectionSchema/CollectionSchemaView.scss | 6 +- .../collectionSchema/CollectionSchemaView.tsx | 5 +- 3 files changed, 109 insertions(+), 33 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/package-lock.json b/package-lock.json index a231d474f..db49a5c24 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2456,7 +2456,7 @@ "@types/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=", + "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", "dev": true }, "@types/strip-json-comments": { @@ -2807,7 +2807,7 @@ "textarea-caret": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/textarea-caret/-/textarea-caret-3.0.2.tgz", - "integrity": "sha512-gRzeti2YS4did7UJnPQ47wrjD+vp+CJIe9zbsu0bJ987d8QVLvLNG9757rqiQTIy4hGIeFauTTJt5Xkn51UkXg==" + "integrity": "sha1-82DEhpmqGr9xhoCkOjGoUGZcLK8=" } } }, @@ -2906,7 +2906,7 @@ "after": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==" + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" }, "agent-base": { "version": "6.0.2", @@ -3803,7 +3803,7 @@ "backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==" + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" }, "bail": { "version": "2.0.2", @@ -3873,7 +3873,7 @@ "base64-arraybuffer": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", - "integrity": "sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==" + "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=" }, "base64-js": { "version": "1.5.1", @@ -4846,7 +4846,7 @@ "component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", - "integrity": "sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw==" + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" }, "component-emitter": { "version": "1.3.0", @@ -4856,7 +4856,7 @@ "component-inherit": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", - "integrity": "sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA==" + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" }, "compress-commons": { "version": "2.1.1", @@ -5563,7 +5563,7 @@ "custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==" + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=" }, "cyclist": { "version": "1.0.1", @@ -5571,10 +5571,52 @@ "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", "dev": true }, - "D": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/D/-/D-1.0.0.tgz", - "integrity": "sha512-nQvrCBu7K2pSSEtIM0EEF03FVjcczCXInMt3moLNFbjlWx6bZrX72uT6/1uAXDbnzGUAx9gTyDiQ+vrFi663oA==" + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "d3": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.4.tgz", + "integrity": "sha512-q2WHStdhiBtD8DMmhDPyJmXUxr6VWRngKyiJ5EfXMxPw+tqT6BhNjhJZ4w3BHsNm3QoVfZLY8Orq/qPFczwKRA==", + "requires": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + } }, "d3-array": { "version": "3.2.2", @@ -6634,7 +6676,7 @@ "dynamic-dedupe": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", - "integrity": "sha1-BuRMIj9eTpTXjvnbI6ZRXOL5YqE=", + "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", "dev": true, "requires": { "xtend": "^4.0.0" @@ -6764,7 +6806,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "ws": { "version": "7.4.6", @@ -6948,6 +6990,28 @@ "is-symbol": "^1.0.2" } }, + "es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, "es6-promise": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz", @@ -9272,7 +9336,7 @@ "fs-extra": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", - "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", + "integrity": "sha512-waKu+1KumRhYv8D8gMRCKJGAMI9pRnPuEb1mvgYD0f7wBscg+h6bW4FDTmEZhB9VKxvoTtxW+Y7bnIlB7zja6Q==", "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^2.1.0", @@ -9932,14 +9996,14 @@ "isarray": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==" + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" } } }, "has-cors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==" + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" }, "has-flag": { "version": "3.0.0", @@ -10434,7 +10498,7 @@ "resolved": "https://registry.npmjs.org/image-size-stream/-/image-size-stream-1.1.0.tgz", "integrity": "sha1-Ivou2mbG31AQh0bacUkmSy0l+Gs=", "requires": { - "image-size": "git+https://github.com/netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1", + "image-size": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1", "readable-stream": "^1.0.33", "tryit": "^1.0.1" }, @@ -10515,7 +10579,7 @@ "indexof": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==" + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" }, "inflight": { "version": "1.0.6", @@ -11626,7 +11690,7 @@ "jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", "requires": { "graceful-fs": "^4.1.6" } @@ -12049,7 +12113,7 @@ "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" }, "lodash.isplainobject": { "version": "4.0.6", @@ -12310,7 +12374,7 @@ "mathquill": { "version": "0.10.1-a", "resolved": "https://registry.npmjs.org/mathquill/-/mathquill-0.10.1-a.tgz", - "integrity": "sha512-snSAEwAtwdwBFSor+nVBnWWQtTw67kgAgKMyAIxuz4ZPboy0qkWZmd7BL3lfOXp/INihhRlU1PcfaAtDaRhmzA==", + "integrity": "sha1-vyylaQEAY6w0vNXVKa3Ag3zVPD8=", "requires": { "jquery": "^1.12.3" }, @@ -12318,7 +12382,7 @@ "jquery": { "version": "1.12.4", "resolved": "https://registry.npmjs.org/jquery/-/jquery-1.12.4.tgz", - "integrity": "sha512-UEVp7PPK9xXYSk8xqXCJrkXnKZtlgWkd2GsAQbMRFK6S/ePU2JN5G2Zum8hIVjzR3CpdfSqdqAzId/xd4TJHeg==" + "integrity": "sha1-AeHfuikP5z3rp3zurLD5ui/sngw=" } } }, @@ -19101,8 +19165,15 @@ "react-resizable-rotatable-draggable": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/react-resizable-rotatable-draggable/-/react-resizable-rotatable-draggable-0.2.0.tgz", - "integrity": "sha512-F8TPx3z7/AcmRViySbYV3LpUWXFpHlGAmKmNcYMgPlS+h1eYFazRG3xYS8Z6e48hWY1EcCny/YNrwRNUrap8CQ==", - "requires": {} + "integrity": "sha512-F8TPx3z7/AcmRViySbYV3LpUWXFpHlGAmKmNcYMgPlS+h1eYFazRG3xYS8Z6e48hWY1EcCny/YNrwRNUrap8CQ==" + }, + "react-resize-detector": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-7.1.2.tgz", + "integrity": "sha512-zXnPJ2m8+6oq9Nn8zsep/orts9vQv3elrpA+R8XTcW7DVVUJ9vwDwMXaBtykAYjMnkCIaOoK9vObyR7ZgFNlOw==", + "requires": { + "lodash": "^4.17.21" + } }, "react-reveal": { "version": "1.2.2", @@ -21694,7 +21765,7 @@ "to-array": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", - "integrity": "sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A==" + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" }, "to-fast-properties": { "version": "2.0.0", @@ -22066,7 +22137,7 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true } } @@ -23287,7 +23358,7 @@ "resolve-cwd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "integrity": "sha512-ccu8zQTrzVr954472aUVPLEcB3YpKSYR3cg/3lo1okzobPBM+1INXBbBZlDbnI/hbEocnf8j0QVo43hQKrbchg==", "dev": true, "requires": { "resolve-from": "^3.0.0" @@ -23296,7 +23367,7 @@ "resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", "dev": true }, "semver": { @@ -23848,7 +23919,7 @@ "yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==" + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" }, "yn": { "version": "3.1.1", diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 1ef2fb4ef..6118aef3f 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -9,7 +9,11 @@ .schema-table { background-color: $white; cursor: grab; - overflow: scroll; + + .schema-table-content { + overflow: overlay; + scroll-behavior: smooth; + } .schema-column-menu, .schema-filter-menu { diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 632abd6cf..46ab08dcd 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -45,6 +45,7 @@ export class CollectionSchemaView extends CollectionSubView() { public static _minColWidth: number = 25; public static _rowMenuWidth: number = 60; public static _previewDividerWidth: number = 4; + public static _newNodeInputHeight: number = 30; @computed get _selectedDocs() { return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.context), this.props.Document)); @@ -778,7 +779,7 @@ export class CollectionSchemaView extends CollectionSubView() { {this._filterColumnIndex !== undefined && this.renderFilterMenu} - + {this.previewWidth > 0 &&
} {this.previewWidth > 0 && ( @@ -833,7 +834,7 @@ class CollectionSchemaViewDocs extends React.Component () => this.props.schema.props.ScreenToLocalTransform().translate(0, -CollectionSchemaView._rowHeight - index * this.rowHeightFunc())); render() { return ( -
+
{this.props.childDocs().docs.map((doc: Doc, index: number) => { const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField ? undefined : this.props.schema.props.DataDoc; return ( -- cgit v1.2.3-70-g09d2 From 12e832da09870c1b08020f3feab327b506893175 Mon Sep 17 00:00:00 2001 From: mehekj Date: Tue, 11 Apr 2023 12:51:13 -0400 Subject: some fixes to schema filtering, wip --- .../collectionSchema/CollectionSchemaView.tsx | 49 ++++++++-------------- 1 file changed, 18 insertions(+), 31 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 46ab08dcd..245e1abc0 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -3,7 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, ObservableMap, untracked } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; -import { Doc, Field, StrListCast } from '../../../../fields/Doc'; +import { Doc, DocListCast, Field, StrListCast } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; import { listSpec } from '../../../../fields/Schema'; @@ -61,7 +61,7 @@ export class CollectionSchemaView extends CollectionSubView() { @observable _newFieldType: ColumnType = ColumnType.Number; @observable _menuValue: string = ''; @observable _filterColumnIndex: number | undefined; - @observable _filterValue: string = ''; + @observable _filterSearchValue: string = ''; get documentKeys() { const docs = this.childDocs; @@ -483,24 +483,17 @@ export class CollectionSchemaView extends CollectionSubView() { @action openFilterMenu = (index: number) => { this._filterColumnIndex = index; - this._filterValue = this.getFieldFilters(this.columnKeys[this._filterColumnIndex!]).map(filter => filter.split(':')[1])[0]; + this._filterSearchValue = ''; }; @action - closeFilterMenu = (setValue: boolean) => { - if (setValue) { - if (this._filterValue !== '') { - Doc.setDocFilter(this.Document, this.columnKeys[this._filterColumnIndex!], this._filterValue, 'check', false, undefined, false); - } else { - this.removeFieldFilters(this.columnKeys[this._filterColumnIndex!]); - } - } + closeFilterMenu = () => { this._filterColumnIndex = undefined; }; openContextMenu = (x: number, y: number, index: number) => { this.closeColumnMenu(); - this.closeFilterMenu(false); + this.closeFilterMenu(); ContextMenu.Instance.clearItems(); ContextMenu.Instance.addItem({ description: 'Change field', @@ -533,15 +526,16 @@ export class CollectionSchemaView extends CollectionSubView() { }; onFilterKeyDown = (e: React.KeyboardEvent) => { - //prettier-ignore switch (e.key) { - case 'Enter' : this.closeFilterMenu(true); break; - case 'Escape': this.closeFilterMenu(false);break; + case 'Enter': + case 'Escape': + this.closeFilterMenu(); + break; } }; @action - updateFilterSearch = (e: React.ChangeEvent) => (this._filterValue = e.target.value); + updateFilterSearch = (e: React.ChangeEvent) => (this._filterSearchValue = e.target.value); @computed get newFieldMenu() { return ( @@ -660,21 +654,16 @@ export class CollectionSchemaView extends CollectionSubView() { @computed get renderFilterOptions() { const keyOptions: string[] = []; const columnKey = this.columnKeys[this._filterColumnIndex!]; - this.childDocs.forEach(doc => { - const key = StrCast(doc[columnKey]); - if (keyOptions.includes(key) === false && (key.includes(this._filterValue) || !this._filterValue) && key !== '') { - keyOptions.push(key); + const allDocs = DocListCast(this.dataDoc[this.props.fieldKey]); + allDocs.forEach(doc => { + const value = StrCast(doc[columnKey]); + if (!keyOptions.includes(value) && value !== '' && (this._filterSearchValue === '' || value.includes(this._filterSearchValue))) { + keyOptions.push(value); } }); const filters = StrListCast(this.Document._docFilters); - for (let i = 0; i < (filters?.length ?? 0) - 1; i++) { - if (filters[i] === columnKey && keyOptions.includes(filters[i].split(':')[1]) === false) { - keyOptions.push(filters[i + 1]); - } - } - - const options = keyOptions.map(key => { + return keyOptions.map(key => { let bool = false; if (filters !== undefined) { const ind = filters.findIndex(filter => filter.split(':')[1] === key); @@ -700,21 +689,19 @@ export class CollectionSchemaView extends CollectionSubView() {
); }); - - return options; } @computed get renderFilterMenu() { const x = this.displayColumnWidths.reduce((total, curr, index) => total + (index < this._filterColumnIndex! ? curr : 0), CollectionSchemaView._rowMenuWidth); return (
- e.stopPropagation()} /> + e.stopPropagation()} /> {this.renderFilterOptions}
{ e.stopPropagation(); - this.closeFilterMenu(true); + this.closeFilterMenu(); })}> done
-- cgit v1.2.3-70-g09d2 From fb9ec75c46bc237bc6c8df24ee998e6de90168a1 Mon Sep 17 00:00:00 2001 From: mehekj 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') 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; // 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) => { 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]) => (
{ e.stopPropagation(); this.setKey(key); }}> - {key} +

+ + {key} + {info.type ? ', ' : ''} + + + {info.type} + +

+

{info.description}

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

{key} - {info.type ? ', ' : ''} + {info.fieldType ? ', ' : ''} - {info.type} + {info.fieldType}

{info.description}

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 { 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 { }; return ( -
-
- } - 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} - /> -
+
+ } + 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} + /> +
+ ); + } + + getCellWithContent(content: any) { + return ( +
+ {content}
); } + + 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 ; + case ColumnType.Date: + return ; + 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 ; + } + + 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 ? ( +
(this._pickingDate = true))}>{this.defaultCellContent}
+ ) : ( + { + 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 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') 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() { return (
{ 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 { }; return ( -
+
} GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)} @@ -76,9 +76,7 @@ export class SchemaTableCell extends React.Component { getCellWithContent(content: any) { return ( -
+
{content}
); @@ -107,7 +105,7 @@ export class SchemaTableCell extends React.Component { case ColumnType.Image: return ; case ColumnType.Date: - return ; + // return ; default: return this.getCellWithContent(this.defaultCellContent); } @@ -117,16 +115,18 @@ export class SchemaTableCell extends React.Component { // 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 ; + return ; } render() { @@ -171,18 +200,8 @@ export class SchemaDateCell extends SchemaTableCell { }; get content() { - return !this._pickingDate ? ( -
(this._pickingDate = true))}>{this.defaultCellContent}
- ) : ( - { - this.handleChange(date); - this._pickingDate = false; - }} - onChange={(date: any) => this.handleChange(date)} - /> - ); + return this.handleChange(date)} />; + // return !this._pickingDate ?
(this._pickingDate = true))}>{this.defaultCellContent}
: this.handleChange(date)} />; } render() { -- cgit v1.2.3-70-g09d2 From 09383542d6b7550f78bc8fba70861454825af150 Mon Sep 17 00:00:00 2001 From: mehekj Date: Wed, 26 Apr 2023 17:22:58 -0400 Subject: fixed schema row arrow key movement and scrolling --- .../collectionSchema/CollectionSchemaView.tsx | 45 +++++++++++++++------- 1 file changed, 31 insertions(+), 14 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 1f76c8099..f1bbc76b4 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -51,6 +51,7 @@ export class CollectionSchemaView extends CollectionSubView() { private _previewRef: HTMLDivElement | null = null; private _makeNewColumn: boolean = false; private _documentOptions: DocumentOptions = new DocumentOptions(); + private _tableContentRef: HTMLDivElement | null = null; public static _rowHeight: number = 50; public static _minColWidth: number = 25; @@ -147,7 +148,7 @@ export class CollectionSchemaView extends CollectionSubView() { } rowIndex(doc: Doc) { - return this.childDocs.indexOf(doc); + return this.sortedDocs.docs.indexOf(doc); } componentDidMount() { @@ -167,28 +168,34 @@ export class CollectionSchemaView extends CollectionSubView() { { const lastDoc = this._selectedDocs.lastElement(); const lastIndex = this.rowIndex(lastDoc); - const curDoc = this.childDocs[lastIndex]; + const curDoc = this.sortedDocs.docs[lastIndex]; + // const curDoc = this.childDocs[lastIndex]; if (lastIndex >= 0 && lastIndex < this.childDocs.length - 1) { !e.shiftKey && this.clearSelection(); - const newDoc = this.childDocs[lastIndex + 1]; + const newDoc = this.sortedDocs.docs[lastIndex + 1]; if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc)); else this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1); + this.scrollToDoc(newDoc, {}); } e.stopPropagation(); + e.preventDefault(); } break; case 'ArrowUp': { const firstDoc = this._selectedDocs.lastElement(); const firstIndex = this.rowIndex(firstDoc); - const curDoc = this.childDocs[firstIndex]; + // const curDoc = this.childDocs[firstIndex]; + const curDoc = this.sortedDocs.docs[firstIndex]; if (firstIndex > 0 && firstIndex < this.childDocs.length) { !e.shiftKey && this.clearSelection(); - const newDoc = this.childDocs[firstIndex - 1]; + const newDoc = this.sortedDocs.docs[firstIndex - 1]; if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc)); else this.addDocToSelection(newDoc, e.shiftKey, firstIndex - 1); + this.scrollToDoc(newDoc, {}); } e.stopPropagation(); + e.preventDefault(); } break; } @@ -474,18 +481,21 @@ export class CollectionSchemaView extends CollectionSubView() { focusDocument = (doc: Doc, options: DocFocusOptions) => { Doc.BrushDoc(doc); + this.scrollToDoc(doc, options); + return undefined; + }; - const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); + scrollToDoc = (doc: Doc, options: DocFocusOptions) => { + const found = this._tableContentRef && Array.from(this._tableContentRef.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); if (found) { - const top = found.getBoundingClientRect().top; - const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top); - if (Math.floor(localTop[1]) !== 0) { - let focusSpeed = options.zoomTime ?? 500; - smoothScroll(focusSpeed, this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc); + const rect = found.getBoundingClientRect(); + const localRect = this.props.ScreenToLocalTransform().transformBounds(rect.left, rect.top, rect.width, rect.height); + if (localRect.y < CollectionSchemaView._rowHeight || localRect.y + localRect.height > this.props.PanelHeight()) { + let focusSpeed = options.zoomTime ?? 100; + smoothScroll(focusSpeed, this._tableContentRef!, localRect.y + this._tableContentRef!.scrollTop - CollectionSchemaView._rowHeight, options.easeFunc); return focusSpeed; } } - return undefined; }; @computed get fieldDefaultInput() { @@ -840,7 +850,13 @@ export class CollectionSchemaView extends CollectionSubView() {
{this._columnMenuIndex !== undefined && this.renderColumnMenu} {this._filterColumnIndex !== undefined && this.renderFilterMenu} - + { + this._tableContentRef = ref; + }} + />
{this.previewWidth > 0 &&
} @@ -884,6 +900,7 @@ export class CollectionSchemaView extends CollectionSubView() { interface CollectionSchemaViewDocsProps { schema: CollectionSchemaView; + setRef: (ref: HTMLDivElement | null) => void; childDocs: () => { docs: Doc[] }; } @@ -894,7 +911,7 @@ class CollectionSchemaViewDocs extends React.Component () => this.props.schema.props.ScreenToLocalTransform().translate(0, -CollectionSchemaView._rowHeight - index * this.rowHeightFunc())); render() { return ( -
+
{this.props.childDocs().docs.map((doc: Doc, index: number) => { const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField ? undefined : this.props.schema.props.DataDoc; return ( -- cgit v1.2.3-70-g09d2 From d58a3350b1d90f701f5cc18a69f51954c88ea30c Mon Sep 17 00:00:00 2001 From: mehekj Date: Wed, 26 Apr 2023 17:34:01 -0400 Subject: fixed selection with sorted docs --- .../collections/collectionSchema/CollectionSchemaView.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index f1bbc76b4..f6dc2a3d7 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -382,17 +382,17 @@ export class CollectionSchemaView extends CollectionSubView() { clearSelection = () => SelectionManager.DeselectAll(); selectRows = (rootDoc: Doc, lastSelected: Doc) => { - const index = this.childDocs.indexOf(rootDoc); - const lastSelectedRow = this.childDocs.indexOf(lastSelected); + const index = this.rowIndex(rootDoc); + const lastSelectedRow = this.rowIndex(lastSelected); const startRow = Math.min(lastSelectedRow, index); const endRow = Math.max(lastSelectedRow, index); for (let i = startRow; i <= endRow; i++) { - const currDoc = this.childDocs[i]; + const currDoc = this.sortedDocs.docs[i]; if (!this._selectedDocs.includes(currDoc)) this.addDocToSelection(currDoc, true, i); } }; - sortedSelectedDocs = () => this.childDocs.filter(doc => this._selectedDocs.includes(doc)); + sortedSelectedDocs = () => this.sortedDocs.docs.filter(doc => this._selectedDocs.includes(doc)); setDropIndex = (index: number) => (this._closestDropIndex = index); @@ -491,7 +491,7 @@ export class CollectionSchemaView extends CollectionSubView() { const rect = found.getBoundingClientRect(); const localRect = this.props.ScreenToLocalTransform().transformBounds(rect.left, rect.top, rect.width, rect.height); if (localRect.y < CollectionSchemaView._rowHeight || localRect.y + localRect.height > this.props.PanelHeight()) { - let focusSpeed = options.zoomTime ?? 100; + let focusSpeed = options.zoomTime ?? 50; smoothScroll(focusSpeed, this._tableContentRef!, localRect.y + this._tableContentRef!.scrollTop - CollectionSchemaView._rowHeight, options.easeFunc); return focusSpeed; } -- cgit v1.2.3-70-g09d2 From bc550e43b6042176cf59f04cbff51e1b21adaa8a Mon Sep 17 00:00:00 2001 From: mehekj 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') 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([...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() { { - 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 { return (
(this._editorRef = ref)} contents={} 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 { } return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value); }} - editing={this.props.isRowActive() ? undefined : false} + editing={this.selected ? undefined : false} />
); } - getCellWithContent(content: any) { - return ( -
- {content} -
- ); - } - get getCellType() { const columnTypeStr = this.props.schemaView?.fieldInfos[this.props.fieldKey]?.fieldType; if (columnTypeStr) { @@ -99,7 +108,7 @@ export class SchemaTableCell extends React.Component { 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 { case ColumnType.Date: // return ; default: - return this.getCellWithContent(this.defaultCellContent); + return this.defaultCellContent; } } + + render() { + return ( +
{ + 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} +
+ ); + } } // 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 { @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 ; } - - render() { - return this.getCellWithContent(this.content); - } } @observer -export class SchemaDateCell extends SchemaTableCell { +export class SchemaDateCell extends React.Component { @observable _pickingDate: boolean = false; @computed get date(): DateField { @@ -199,12 +217,7 @@ export class SchemaDateCell extends SchemaTableCell { //} }; - get content() { - return this.handleChange(date)} />; - // return !this._pickingDate ?
(this._pickingDate = true))}>{this.defaultCellContent}
: this.handleChange(date)} />; - } - render() { - return this.getCellWithContent(this.content); + return this.handleChange(date)} />; } } -- cgit v1.2.3-70-g09d2 From b82a909a63a6de414d075735453240ebc02f5aa3 Mon Sep 17 00:00:00 2001 From: mehekj 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') 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 { 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() { 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() { 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} /> ))}
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 { 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 { 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 { } 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 {
{ - 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 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') 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() { })} /> -
- {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))} -
+ {!this.layoutDoc.linearViewIsExpanded ? null : ( +
+ {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))} +
+ )}
); 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(); - @computed get _selectedDocs() { - return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.context), this.props.Document)); - } + @observable _menuKeys: string[] = []; @observable _rowEles: ObservableMap = new ObservableMap(); @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, + 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) => { 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 => (
{ @@ -742,13 +731,13 @@ export class CollectionSchemaView extends CollectionSubView() {

{key} - {info.fieldType ? ', ' : ''} + {this.fieldInfos.get(key)!.fieldType ? ', ' : ''} - - {info.fieldType} + + {this.fieldInfos.get(key)!.fieldType}

-

{info.description}

+

{this.fieldInfos.get(key)!.description}

))}
@@ -888,13 +877,7 @@ export class CollectionSchemaView extends CollectionSubView() {
{this._columnMenuIndex !== undefined && this.renderColumnMenu} {this._filterColumnIndex !== undefined && this.renderFilterMenu} - { - this._tableContentRef = ref; - }} - /> + (this._tableContentRef = ref)} />
{this.previewWidth > 0 &&
} @@ -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 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() { @@ -24,12 +26,9 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { 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() { 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 (
() { 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} /> ))}
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 { 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 { 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 { 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 { 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 { } 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 {
{ - if (!this.selected) this.props.schemaView()?.selectCell(this.props.Document, this.props.col); + if (!this.selected) this.props.selectCell(this.props.Document, this.props.col); })} style={{ width: this.props.columnWidth, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}> {this.content} -- cgit v1.2.3-70-g09d2 From 51fbd118b00f4baebeed989bcd33000ac345ec8c Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 27 Apr 2023 20:28:31 -0400 Subject: fixed retrieving fields in schema view. --- .../views/collections/collectionSchema/CollectionSchemaView.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 50a91a60a..3dff8d769 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1,6 +1,6 @@ import React = require('react'); import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable, ObservableMap, observe, reaction, trace, untracked } from 'mobx'; +import { action, computed, observable, ObservableMap, observe, trace } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import { Doc, DocListCast, Field, NumListCast, StrListCast } from '../../../../fields/Doc'; @@ -16,6 +16,7 @@ import { SelectionManager } from '../../../util/SelectionManager'; import { undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { EditableView } from '../../EditableView'; +import { Colors } from '../../global/globalEnums'; import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { KeyValueBox } from '../../nodes/KeyValueBox'; @@ -24,7 +25,6 @@ import { CollectionSubView } from '../CollectionSubView'; import './CollectionSchemaView.scss'; import { SchemaColumnHeader } from './SchemaColumnHeader'; import { SchemaRowBox } from './SchemaRowBox'; -import { Colors } from '../../global/globalEnums'; export enum ColumnType { Number, @@ -134,7 +134,7 @@ export class CollectionSchemaView extends CollectionSubView() { // prettier-ignore (change as any).added.forEach((doc: Doc) => // for each document added Doc.GetAllPrototypes(doc).forEach(proto => // for all of its prototypes (and itself) - Object.keys(proto).forEach(action(key => // check if any of its keys are new, and add them + Object.keys(proto.value as Doc).forEach(action(key => // check if any of its keys are new, and add them !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo('')))))); break; case 'update': //let oldValue = change.oldValue; // fill this in if the entire child list will ever be reassigned with a new list -- cgit v1.2.3-70-g09d2 From 08d94147eb855bbb3d7eb964ffa6a7a3248001a2 Mon Sep 17 00:00:00 2001 From: bobzel 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') 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, props: Opt { 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 ( -
+
(this._editorRef = ref)} contents={} -- cgit v1.2.3-70-g09d2 From cc62b9949854f27bc19eb8d4224456094f0dbe13 Mon Sep 17 00:00:00 2001 From: bobzel 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') 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 { 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 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') 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() { 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 (
() { 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 { - 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 (
(this._editorRef = ref)} - contents={} + contents={} + 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} + })} />
); @@ -146,13 +131,12 @@ export class SchemaTableCell extends React.Component { get content() { const cellType: ColumnType = this.getCellType; + // prettier-ignore switch (cellType) { - case ColumnType.Image: - return ; - case ColumnType.Date: - // return ; - default: - return this.defaultCellContent; + case ColumnType.Image: return ; + case ColumnType.Boolean: return ; + case ColumnType.Date: // return ; + default: return this.defaultCellContent; } } @@ -160,10 +144,8 @@ export class SchemaTableCell extends React.Component { return (
{ - 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}
); @@ -257,3 +239,39 @@ export class SchemaDateCell extends React.Component { return this.handleChange(date)} />; } } +@observer +export class SchemaBoolCell extends React.Component { + @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 ( +
+ | 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()); + })} + /> + } + 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); + })} + /> +
+ ); + } +} 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 { public static LayoutString() { -- cgit v1.2.3-70-g09d2 From 773164e71dd6420d5ee669b138f2b6ba05164874 Mon Sep 17 00:00:00 2001 From: bobzel 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') 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 { 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); })} />
@@ -255,7 +255,7 @@ export class SchemaBoolCell extends React.Component { checked={BoolCast(this.props.Document[this.props.fieldKey])} onChange={undoBatch((value: React.ChangeEvent | 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 { 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 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') 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 { } 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 c6fc5badaac451f16d9a537c8bda84e359bb0182 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 27 Apr 2023 23:11:25 -0400 Subject: another fix for fieldInfos --- .../views/collections/collectionSchema/CollectionSchemaView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 3dff8d769..3f7e037d4 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -133,8 +133,8 @@ export class CollectionSchemaView extends CollectionSubView() { case 'splice': // prettier-ignore (change as any).added.forEach((doc: Doc) => // for each document added - Doc.GetAllPrototypes(doc).forEach(proto => // for all of its prototypes (and itself) - Object.keys(proto.value as Doc).forEach(action(key => // check if any of its keys are new, and add them + Doc.GetAllPrototypes(doc.value as Doc).forEach(proto => // for all of its prototypes (and itself) + Object.keys(proto).forEach(action(key => // check if any of its keys are new, and add them !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo('')))))); break; case 'update': //let oldValue = change.oldValue; // fill this in if the entire child list will ever be reassigned with a new list -- cgit v1.2.3-70-g09d2 From becc884883df07635f4619f908747598b3eb86ee Mon Sep 17 00:00:00 2001 From: bobzel 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') 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 { } 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 { switch (cellType) { case ColumnType.Image: return ; case ColumnType.Boolean: return ; + case ColumnType.RTF: return ; case ColumnType.Date: // return ; default: return this.defaultCellContent; } @@ -240,6 +243,23 @@ export class SchemaDateCell extends React.Component { } } @observer +export class SchemaRTFCell extends React.Component { + @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 ( +
+ {this.selected ? : (field => (field ? Field.toString(field) : ''))(FieldValue(fieldProps.Document[fieldProps.fieldKey]))} +
+ ); + } +} +@observer export class SchemaBoolCell extends React.Component { @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 { } 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 From dca61505ba138eef3819b16b760ec81becf9329e Mon Sep 17 00:00:00 2001 From: bobzel Date: Sat, 13 May 2023 09:55:48 -0400 Subject: changed EditableViews to support oneline and multiline. Also added transformer UI to allow documents to be entered. changed transformer to write doc id's, not variables.. made schema view support oneline and fixed bug with docdecoration hader occluding things invisibly. updated web pages to be zoomable and for its anchors to update web page and scroll location properly. made autolinkanchor directly go to target on click. --- package-lock.json | 39 +++ src/client/documents/Documents.ts | 4 +- src/client/util/CurrentUserUtils.ts | 5 +- src/client/util/DocumentManager.ts | 24 +- src/client/util/Scripting.ts | 30 +- src/client/views/DocumentDecorations.tsx | 8 +- src/client/views/EditableView.scss | 11 +- src/client/views/EditableView.tsx | 98 ++++-- src/client/views/MarqueeAnnotator.tsx | 3 +- src/client/views/ScriptingRepl.scss | 5 +- src/client/views/ScriptingRepl.tsx | 113 ++++--- .../views/collections/CollectionStackingView.scss | 6 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 18 +- .../collectionSchema/CollectionSchemaView.scss | 4 +- .../collectionSchema/CollectionSchemaView.tsx | 23 +- .../collectionSchema/SchemaColumnHeader.tsx | 1 + .../collections/collectionSchema/SchemaRowBox.tsx | 10 +- .../collectionSchema/SchemaTableCell.tsx | 44 ++- .../views/nodes/CollectionFreeFormDocumentView.tsx | 3 +- src/client/views/nodes/DocumentIcon.tsx | 56 ++-- src/client/views/nodes/DocumentView.tsx | 4 +- src/client/views/nodes/KeyValueBox.tsx | 6 +- src/client/views/nodes/KeyValuePair.scss | 64 ++-- src/client/views/nodes/KeyValuePair.tsx | 8 +- src/client/views/nodes/WebBox.tsx | 359 ++++++++++----------- src/client/views/nodes/button/FontIconBox.tsx | 13 +- .../views/nodes/formattedText/DashFieldView.tsx | 150 ++------- .../views/nodes/formattedText/FormattedTextBox.tsx | 3 +- src/client/views/nodes/formattedText/marks_rts.ts | 2 +- src/client/views/nodes/trails/PresBox.tsx | 18 +- src/client/views/pdf/PDFViewer.tsx | 3 +- src/fields/Doc.ts | 2 +- 32 files changed, 605 insertions(+), 532 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/package-lock.json b/package-lock.json index 196906718..111d1838a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5597,6 +5597,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", @@ -6977,6 +6987,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", @@ -6988,6 +7020,7 @@ "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", "dev": true, "requires": { + "d": "^1.0.1", "ext": "^1.1.2" } }, @@ -22660,6 +22693,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/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 5a7894c08..bb12ce568 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1054,8 +1054,8 @@ export namespace Docs { return inst; } - export function WebanchorDocument(url?: string, options: DocumentOptions = {}, id?: string) { - return InstanceFromProto(Prototypes.get(DocumentType.MARKER), url, options, id); + export function WebanchorDocument(options: DocumentOptions = {}, id?: string) { + return InstanceFromProto(Prototypes.get(DocumentType.MARKER), undefined, options, id); } export function CollectionAnchorDocument(options: DocumentOptions = {}, id?: string) { diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 80a5f0993..fbfe306a4 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -669,7 +669,10 @@ export class CurrentUserUtils { } static schemaTools():Button[] { - return [{ title: "Show preview", toolTip: "Show selection preview", btnType: ButtonType.ToggleButton, buttonText: "Show Preview", icon: "eye", scripts:{ onClick: '{ return toggleSchemaPreview(_readOnly_); }'}, }]; + return [ + {title: "Show preview", toolTip: "Show selection preview", btnType: ButtonType.ToggleButton, buttonText: "Show Preview", icon: "eye", scripts:{ onClick: '{ return toggleSchemaPreview(_readOnly_); }'} }, + {title: "Single Lines", toolTip: "Single Line Rows", btnType: ButtonType.ToggleButton, buttonText: "Single Line", icon: "eye", scripts:{ onClick: '{ return toggleSingleLineSchema(_readOnly_); }'} }, + ]; } static webTools() { diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 3a192f712..695b003a6 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,4 +1,4 @@ -import { action, observable, ObservableSet } from 'mobx'; +import { action, computed, observable, ObservableSet } from 'mobx'; import { AnimationSym, Doc, Opt } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; import { listSpec } from '../../fields/Schema'; @@ -10,6 +10,7 @@ import { TabDocView } from '../views/collections/TabDocView'; import { LightboxView } from '../views/LightboxView'; import { DocFocusOptions, DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView'; import { FormattedTextBox } from '../views/nodes/formattedText/FormattedTextBox'; +import { KeyValueBox } from '../views/nodes/KeyValueBox'; import { LinkAnchorBox } from '../views/nodes/LinkAnchorBox'; import { PresBox } from '../views/nodes/trails'; import { ScriptingGlobals } from './ScriptingGlobals'; @@ -18,10 +19,13 @@ const { Howl } = require('howler'); export class DocumentManager { //global holds all of the nodes (regardless of which collection they're in) - @observable public DocumentViews = new Set(); + @observable _documentViews = new Set(); @observable public LinkAnchorBoxViews: DocumentView[] = []; @observable public RecordingEvent = 0; @observable public LinkedDocumentViews: { a: DocumentView; b: DocumentView; l: Doc }[] = []; + @computed public get DocumentViews() { + return Array.from(this._documentViews).filter(view => !(view.ComponentView instanceof KeyValueBox)); + } private static _instance: DocumentManager; public static get Instance(): DocumentManager { @@ -78,7 +82,7 @@ export class DocumentManager { // this.LinkedDocumentViews.forEach(view => console.log(" LV = " + view.a.props.Document.title + "/" + view.a.props.LayoutTemplateString + " --> " + // view.b.props.Document.title + "/" + view.b.props.LayoutTemplateString)); } else { - this.DocumentViews.add(view); + this._documentViews.add(view); } this.callAddViewFuncs(view); }; @@ -96,7 +100,7 @@ export class DocumentManager { const index = this.LinkAnchorBoxViews.indexOf(view); this.LinkAnchorBoxViews.splice(index, 1); } else { - this.DocumentViews.delete(view); + this._documentViews.delete(view); } SelectionManager.DeselectView(view); }); @@ -104,13 +108,13 @@ export class DocumentManager { //gets all views public getDocumentViewsById(id: string) { const toReturn: DocumentView[] = []; - Array.from(DocumentManager.Instance.DocumentViews).map(view => { + DocumentManager.Instance.DocumentViews.forEach(view => { if (view.rootDoc[Id] === id) { toReturn.push(view); } }); if (toReturn.length === 0) { - Array.from(DocumentManager.Instance.DocumentViews).map(view => { + DocumentManager.Instance.DocumentViews.forEach(view => { const doc = view.rootDoc.proto; if (doc && doc[Id] && doc[Id] === id) { toReturn.push(view); @@ -133,7 +137,7 @@ export class DocumentManager { // ((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; - const docViewArray = Array.from(DocumentManager.Instance.DocumentViews); + const docViewArray = DocumentManager.Instance.DocumentViews; const passes = !doc ? [] : preferredCollection ? [preferredCollection, undefined] : [undefined]; return passes.reduce( (pass, toReturn) => @@ -146,7 +150,7 @@ export class DocumentManager { public getLightboxDocumentView = (toFind: Doc, originatingDoc: Opt = undefined): DocumentView | undefined => { const views: DocumentView[] = []; - Array.from(DocumentManager.Instance.DocumentViews).map(view => LightboxView.IsLightboxDocView(view.docViewPath) && Doc.AreProtosEqual(view.rootDoc, toFind) && views.push(view)); + DocumentManager.Instance.DocumentViews.forEach(view => LightboxView.IsLightboxDocView(view.docViewPath) && Doc.AreProtosEqual(view.rootDoc, toFind) && views.push(view)); return views?.find(view => view.ContentDiv?.getBoundingClientRect().width /*&& view.props.focus !== returnFalse) || views?.find(view => view.props.focus !== returnFalse*/) || (views.length ? views[0] : undefined); }; public getFirstDocumentView = (toFind: Doc, originatingDoc: Opt = undefined): DocumentView | undefined => { @@ -164,8 +168,8 @@ export class DocumentManager { toFindIn; const toReturn: DocumentView[] = []; - const docViews = Array.from(DocumentManager.Instance.DocumentViews).filter(view => !LightboxView.IsLightboxDocView(view.docViewPath)); - const lightViews = Array.from(DocumentManager.Instance.DocumentViews).filter(view => LightboxView.IsLightboxDocView(view.docViewPath)); + const docViews = DocumentManager.Instance.DocumentViews.filter(view => !LightboxView.IsLightboxDocView(view.docViewPath)); + const lightViews = DocumentManager.Instance.DocumentViews.filter(view => LightboxView.IsLightboxDocView(view.docViewPath)); // heuristic to return the "best" documents first: // choose a document in the lightbox first diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index f17a98616..70c2e3842 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -7,8 +7,6 @@ import * as typescriptlib from '!!raw-loader!./type_decls.d'; import * as ts from 'typescript'; import { Doc, Field } from '../../fields/Doc'; -import { ToScriptString } from '../../fields/FieldSymbols'; -import { ObjectField } from '../../fields/ObjectField'; import { RefField } from '../../fields/RefField'; import { ScriptField } from '../../fields/ScriptField'; import { scriptingGlobals, ScriptingGlobals } from './ScriptingGlobals'; @@ -60,7 +58,14 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an // let fieldTypes = [Doc, ImageField, PdfField, VideoField, AudioField, List, RichTextField, ScriptField, ComputedField, CompileScript]; // let paramNames = ["Docs", ...fieldTypes.map(fn => fn.name)]; // let params: any[] = [Docs, ...fieldTypes]; - const compiledFunction = new Function(...paramNames, `return ${script}`); + const compiledFunction = (() => { + try { + return new Function(...paramNames, `return ${script}`); + } catch { + return undefined; + } + })(); + if (!compiledFunction) return { compiled: false, errors }; const { capturedVariables = {} } = options; const run = (args: { [name: string]: any } = {}, onError?: (e: any) => void, errorVal?: any): ScriptResult => { const argsArray: any[] = []; @@ -155,7 +160,7 @@ export type Traverser = (node: ts.Node, indentation: string) => boolean | void; export type TraverserParam = Traverser | { onEnter: Traverser; onLeave: Traverser }; export type Transformer = { transformer: ts.TransformerFactory; - getVars?: () => { capturedVariables: { [name: string]: Field } }; + getVars?: () => { [name: string]: Field }; }; export interface ScriptOptions { requiredType?: string; // does function required a typed return value @@ -205,16 +210,17 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp if (options.transformer) { const sourceFile = ts.createSourceFile('script.ts', script, ts.ScriptTarget.ES2015, true); const result = ts.transform(sourceFile, [options.transformer.transformer]); - if (options.transformer.getVars) { - const newCaptures = options.transformer.getVars(); + const newCaptures = options.transformer.getVars?.(); + if (Object.keys(newCaptures ?? {}).length) { // tslint:disable-next-line: prefer-object-spread - options.capturedVariables = Object.assign(capturedVariables, newCaptures.capturedVariables) as any; + //options.capturedVariables = Object.assign(capturedVariables, newCaptures!) as any; + + const transformed = result.transformed; + const printer = ts.createPrinter({ + newLine: ts.NewLineKind.LineFeed, + }); + script = printer.printFile(transformed[0]); } - const transformed = result.transformed; - const printer = ts.createPrinter({ - newLine: ts.NewLineKind.LineFeed, - }); - script = printer.printFile(transformed[0]); result.dispose(); } const paramNames: string[] = []; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 85d36dbf8..26b64bfdd 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -867,11 +867,11 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P width: bounds.r - bounds.x + this._resizeBorderWidth + 'px', height: bounds.b - bounds.y + this._resizeBorderWidth + this._titleHeight + 'px', }}> -
- {hideDeleteButton ?
: topBtn('close', 'times', undefined, e => this.onCloseClick(true), 'Close')} - {hideResizers || hideDeleteButton ?
: topBtn('minimize', 'window-maximize', undefined, e => this.onCloseClick(undefined), 'Minimize')} +
+ {hideDeleteButton ? null : topBtn('close', 'times', undefined, e => this.onCloseClick(true), 'Close')} + {hideResizers || hideDeleteButton ? null : topBtn('minimize', 'window-maximize', undefined, e => this.onCloseClick(undefined), 'Minimize')} {hideTitle ? null : titleArea} - {hideOpenButton ?
: topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Lightbox (ctrl: as alias, shift: in new collection)')} + {hideOpenButton ? null : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Lightbox (ctrl: as alias, shift: in new collection)')}
{hideResizers ? null : ( <> diff --git a/src/client/views/EditableView.scss b/src/client/views/EditableView.scss index ed7ec9dc1..0955ba8ff 100644 --- a/src/client/views/EditableView.scss +++ b/src/client/views/EditableView.scss @@ -10,12 +10,14 @@ .editableView-container-editing-oneLine { width: 100%; + height: max-content; span { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - display: block; + p { + white-space: pre; + overflow: hidden; + text-overflow: ellipsis; + } } input { @@ -33,4 +35,3 @@ border: none; outline: none; } - \ No newline at end of file diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index d1311a60a..6b4132814 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -1,9 +1,11 @@ import React = require('react'); -import { action, observable } from 'mobx'; +import { action, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as Autosuggest from 'react-autosuggest'; import { ObjectField } from '../../fields/ObjectField'; import './EditableView.scss'; +import { DocumentIconContainer } from './nodes/DocumentIcon'; +import { OverlayView } from './OverlayView'; export interface EditableProps { /** @@ -37,7 +39,8 @@ export interface EditableProps { onChange: (e: React.ChangeEvent, { newValue }: { newValue: string }) => void; autosuggestProps: Autosuggest.AutosuggestProps; }; - oneLine?: boolean; + oneLine?: boolean; // whether to display the editable view as a single input line or as a textarea + allowCRs?: boolean; // can carriage returns be entered editing?: boolean; isEditingCallback?: (isEditing: boolean) => void; menuCallback?: (x: number, y: number) => void; @@ -45,6 +48,7 @@ export interface EditableProps { showMenuOnLoad?: boolean; background?: string | undefined; placeholder?: string; + wrap?: string; // nowrap, pre-wrap, etc } /** @@ -55,7 +59,9 @@ export interface EditableProps { @observer export class EditableView extends React.Component { private _ref = React.createRef(); - private _inputref = React.createRef(); + private _inputref: HTMLInputElement | HTMLTextAreaElement | null = null; + _overlayDisposer?: () => void; + _editingDisposer?: IReactionDisposer; @observable _editing: boolean = false; constructor(props: EditableProps) { @@ -63,21 +69,53 @@ export class EditableView extends React.Component { this._editing = this.props.editing ? true : false; } + componentDidMount(): void { + this._editingDisposer = reaction( + () => this._editing, + editing => { + if (editing) { + setTimeout(() => { + if (this._inputref?.value.startsWith('=') || this._inputref?.value.startsWith(':=')) { + this._overlayDisposer?.(); + this._overlayDisposer = OverlayView.Instance.addElement(, { x: 0, y: 0 }); + } + }); + } else { + this._overlayDisposer?.(); + this._overlayDisposer = undefined; + } + }, + { fireImmediately: true } + ); + } + @action componentDidUpdate() { if (this._editing && this.props.editing === false) { - this._inputref.current?.value && this.finalizeEdit(this._inputref.current.value, false, true, false); + this._inputref?.value && this.finalizeEdit(this._inputref.value, false, true, false); } else if (this.props.editing !== undefined) { this._editing = this.props.editing; } } componentWillUnmount() { - this._inputref.current?.value && this.finalizeEdit(this._inputref.current.value, false, true, false); + this._overlayDisposer?.(); + this._editingDisposer?.(); + this._inputref?.value && this.finalizeEdit(this._inputref.value, false, true, false); } + onChange = (e: React.ChangeEvent) => { + const targVal = (e.target as any).value; + if (!(targVal.startsWith(':=') || targVal.startsWith('='))) { + this._overlayDisposer?.(); + this._overlayDisposer = undefined; + } else if (!this._overlayDisposer) { + this._overlayDisposer = OverlayView.Instance.addElement(, { x: 0, y: 0 }); + } + }; + @action - onKeyDown = (e: React.KeyboardEvent) => { + onKeyDown = (e: React.KeyboardEvent) => { switch (e.key) { case 'Tab': e.stopPropagation(); @@ -89,13 +127,15 @@ export class EditableView extends React.Component { if (!e.currentTarget.value) this.props.OnEmpty?.(); break; case 'Enter': - e.stopPropagation(); - if (!e.ctrlKey) { - this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, true); - } else if (this.props.OnFillDown) { - this.props.OnFillDown(e.currentTarget.value); - this._editing = false; - this.props.isEditingCallback?.(false); + if (this.props.allowCRs !== true) { + e.stopPropagation(); + if (!e.ctrlKey) { + this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, true); + } else if (this.props.OnFillDown) { + this.props.OnFillDown(e.currentTarget.value); + this._editing = false; + this.props.isEditingCallback?.(false); + } } break; case 'Escape': @@ -103,9 +143,6 @@ export class EditableView extends React.Component { this._editing = false; this.props.isEditingCallback?.(false); break; - case ':': - this.props.menuCallback?.(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y); - break; case 'ArrowUp': case 'ArrowDown': case 'ArrowLeft': @@ -117,6 +154,12 @@ export class EditableView extends React.Component { case 'Meta': case 'Control': break; + case ':': + if (this.props.menuCallback) { + this.props.menuCallback(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y); + break; + } + default: if (this.props.textCallback?.(e.key)) { this._editing = false; @@ -186,15 +229,32 @@ export class EditableView extends React.Component { onChange: this.props.autosuggestProps.onChange, }} /> - ) : ( + ) : this.props.oneLine !== false && this.props.GetValue()?.toString().indexOf('\n') === -1 ? ( (this._inputref = r)} style={{ display: this.props.display, overflow: 'auto', fontSize: this.props.fontSize, minWidth: 20, background: this.props.background }} placeholder={this.props.placeholder} onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)} defaultValue={this.props.GetValue()} autoFocus={true} + onChange={this.onChange} + onKeyDown={this.onKeyDown} + onKeyPress={this.stopPropagation} + onPointerDown={this.stopPropagation} + onClick={this.stopPropagation} + onPointerUp={this.stopPropagation} + /> + ) : ( +