From ce322f1ba1c4f4a85681088c374318a3fb75f56b Mon Sep 17 00:00:00 2001 From: Cristhian Zanforlin Lousa <72977554+Cristhianzl@users.noreply.github.com> Date: Tue, 23 Apr 2024 21:54:01 -0300 Subject: [PATCH] Merge pdfView Branch Features (#1772) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * starting commit from pdfView branch * 📝 (csvOutputComponent/index.tsx): update useEffect dependency array to include 'separator' variable to re-render component when separator changes * 🐛 (csvOutputComponent/index.tsx): handle error when parsing JSON string in file variable assignment to prevent app crash ✨ (csvOutputComponent/index.tsx): add error message and UI when file variable is null to inform user about the error * 📝 (KeyPairInput.py): Add KeyPairInput component to handle dictionary input and return the input value as is 📝 (CSVOutput.py): Add CSVOutput component to handle CSV output with configurable separator 📝 (ImageOutput.py): Add ImageOutput component to handle image output 📝 (PDFOutput.py): Add PDFOutput component to handle PDF output 📝 (constants.ts): Add KeyPairInput to the list of supported input types 📝 (IOModal/index.tsx): Remove console.log statement * 🔧 (KeyPairInput.py): Remove unused KeyPairInput component 🔧 (CSVOutput.py): Remove unused CSVOutput component 🔧 (ImageOutput.py): Remove unused ImageOutput component 🔧 (PDFOutput.py): Remove unused PDFOutput component These components were deleted as they were no longer being used in the project and were causing unnecessary clutter in the codebase. Removing them improves code maintainability and reduces potential confusion for developers working on the project. * 🔧 (IOModal/index.tsx): remove console.log statement for selectedViewField variable to clean up code and improve performance --- src/frontend/package-lock.json | 579 +++++++++++++++++- src/frontend/package.json | 4 + .../src/components/ImageViewer/index.tsx | 141 +++++ .../helpers/convert-data-function.ts | 27 + .../components/csvOutputComponent/index.tsx | 182 ++++++ .../src/components/pdfViewer/Error/index.tsx | 23 + .../src/components/pdfViewer/index.tsx | 155 +++++ .../src/components/pdfViewer/noData/index.tsx | 17 + src/frontend/src/constants/constants.ts | 33 +- .../IOModal/components/IOFieldView/index.tsx | 77 +++ 10 files changed, 1226 insertions(+), 12 deletions(-) create mode 100644 src/frontend/src/components/ImageViewer/index.tsx create mode 100644 src/frontend/src/components/csvOutputComponent/helpers/convert-data-function.ts create mode 100644 src/frontend/src/components/csvOutputComponent/index.tsx create mode 100644 src/frontend/src/components/pdfViewer/Error/index.tsx create mode 100644 src/frontend/src/components/pdfViewer/index.tsx create mode 100644 src/frontend/src/components/pdfViewer/noData/index.tsx diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index 2ec5cdfb3..e7020b2d6 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -31,6 +31,7 @@ "@tailwindcss/line-clamp": "^0.4.4", "@types/axios": "^0.14.0", "ace-builds": "^1.24.1", + "ag-grid-react": "^31.2.1", "ansi-to-html": "^0.7.2", "axios": "^1.5.0", "base64-js": "^1.5.1", @@ -40,11 +41,13 @@ "dompurify": "^3.0.5", "dotenv": "^16.4.5", "esbuild": "^0.17.19", + "file-saver": "^2.0.5", "framer-motion": "^11.0.6", "lodash": "^4.17.21", "lucide-react": "^0.331.0", "million": "^3.0.6", "moment": "^2.29.4", + "openseadragon": "^4.1.1", "playwright": "^1.42.0", "react": "^18.2.0", "react-ace": "^10.1.0", @@ -54,6 +57,7 @@ "react-icons": "^5.0.1", "react-laag": "^2.0.5", "react-markdown": "^8.0.7", + "react-pdf": "^7.7.1", "react-router-dom": "^6.15.0", "react-syntax-highlighter": "^15.5.0", "react18-json-view": "^0.2.3", @@ -1059,6 +1063,59 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, "node_modules/@million/lint": { "version": "0.0.73", "resolved": "https://registry.npmjs.org/@million/lint/-/lint-0.0.73.tgz", @@ -4283,6 +4340,12 @@ "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", "deprecated": "Use your platform's native atob() and btoa() methods instead" }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "optional": true + }, "node_modules/ace-builds": { "version": "1.32.9", "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.32.9.tgz", @@ -4325,6 +4388,24 @@ "node": ">=0.4.0" } }, + "node_modules/ag-grid-community": { + "version": "31.2.1", + "resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-31.2.1.tgz", + "integrity": "sha512-D+gnUQ4dHZ/EQJmupQnDqcEKiCEeuK5ZxlsIpdPKgHg/23dmW+aEdivtB9nLpSc2IEK0RUpchcSxeUT37Boo5A==" + }, + "node_modules/ag-grid-react": { + "version": "31.2.1", + "resolved": "https://registry.npmjs.org/ag-grid-react/-/ag-grid-react-31.2.1.tgz", + "integrity": "sha512-9UH3xxXRwZfW97oz58KboyCJl4t+zdetopieeHVcttsXX1DvGFDUIEz7A1sQaG8e1DAXLMf3IxoIPrfWheH4XA==", + "dependencies": { + "ag-grid-community": "31.2.1", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": "^16.3.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.3.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -4402,6 +4483,12 @@ "node": ">= 8" } }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "optional": true + }, "node_modules/arch": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", @@ -4422,6 +4509,19 @@ } ] }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -4907,6 +5007,21 @@ } ] }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -4990,6 +5105,15 @@ "node": ">= 6" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "optional": true, + "engines": { + "node": ">=10" + } + }, "node_modules/class-variance-authority": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.6.1.tgz", @@ -5095,6 +5219,15 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -5128,7 +5261,13 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "devOptional": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "optional": true }, "node_modules/content-disposition": { "version": "0.5.4", @@ -5583,6 +5722,12 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "optional": true + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -5591,6 +5736,15 @@ "node": ">=6" } }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", @@ -6438,6 +6592,11 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, "node_modules/file-type": { "version": "17.1.6", "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.6.tgz", @@ -6682,11 +6841,41 @@ "node": ">=14.14" } }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "devOptional": true }, "node_modules/fsevents": { "version": "2.3.2", @@ -6718,6 +6907,46 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gauge/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "optional": true + }, + "node_modules/gauge/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -6766,7 +6995,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, + "devOptional": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -6797,7 +7026,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "devOptional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6807,7 +7036,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "devOptional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -6939,6 +7168,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "optional": true + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -7244,7 +7479,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, + "devOptional": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -8253,6 +8488,37 @@ "lz-string": "bin/bin.js" } }, + "node_modules/make-cancellable-promise": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/make-cancellable-promise/-/make-cancellable-promise-1.3.2.tgz", + "integrity": "sha512-GCXh3bq/WuMbS+Ky4JBPW1hYTOU+znU+Q5m9Pu+pI8EoUqIHk9+tviOKC6/qhHh8C4/As3tzJ69IF32kdz85ww==", + "funding": { + "url": "https://github.com/wojtekmaj/make-cancellable-promise?sponsor=1" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "optional": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-event-props": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/make-event-props/-/make-event-props-1.6.2.tgz", + "integrity": "sha512-iDwf7mA03WPiR8QxvcVHmVWEPfMY1RZXerDVNCRYW7dUr2ppH3J58Rwb39/WG39yTZdRSxr3x+2v22tvI0VEvA==", + "funding": { + "url": "https://github.com/wojtekmaj/make-event-props?sponsor=1" + } + }, "node_modules/markdown-table": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", @@ -8501,6 +8767,22 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/merge-refs": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/merge-refs/-/merge-refs-1.2.2.tgz", + "integrity": "sha512-RwcT7GsQR3KbuLw1rRuodq4Nt547BKEBkliZ0qqsrpyNne9bGTFtsFIsIpx82huWhcl3kOlOlH4H0xkPk/DqVw==", + "funding": { + "url": "https://github.com/wojtekmaj/merge-refs?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -9186,6 +9468,37 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, "node_modules/mj-context-menu": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", @@ -9236,6 +9549,12 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nan": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", + "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==", + "optional": true + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -9310,6 +9629,21 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -9360,6 +9694,18 @@ "node": ">=4" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "optional": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/nwsapi": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", @@ -9437,7 +9783,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, + "devOptional": true, "dependencies": { "wrappy": "1" } @@ -9456,6 +9802,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openseadragon": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/openseadragon/-/openseadragon-4.1.1.tgz", + "integrity": "sha512-owU9gsasAcobLN+LM8lN58Xc2VDSDotY9mkrwS/NB6g9KX/PcusV4RZvhHng2RF/Q0pMziwldf62glwXoGnuzg==", + "funding": { + "url": "https://opencollective.com/openseadragon" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -9685,7 +10039,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -9734,6 +10088,27 @@ "node": ">=8" } }, + "node_modules/path2d-polyfill": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", + "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pdfjs-dist": { + "version": "3.11.174", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", + "integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==", + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "canvas": "^2.11.2", + "path2d-polyfill": "^2.0.1" + } + }, "node_modules/peek-readable": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", @@ -10544,6 +10919,43 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, + "node_modules/react-pdf": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-7.7.1.tgz", + "integrity": "sha512-cbbf/PuRtGcPPw+HLhMI1f6NSka8OJgg+j/yPWTe95Owf0fK6gmVY7OXpTxMeh92O3T3K3EzfE0ML0eXPGwR5g==", + "dependencies": { + "clsx": "^2.0.0", + "dequal": "^2.0.3", + "make-cancellable-promise": "^1.3.1", + "make-event-props": "^1.6.0", + "merge-refs": "^1.2.1", + "pdfjs-dist": "3.11.174", + "prop-types": "^15.6.2", + "tiny-invariant": "^1.0.0", + "warning": "^4.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-pdf?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-pdf/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/react-reconciler": { "version": "0.29.0", "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz", @@ -10967,7 +11379,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, + "devOptional": true, "dependencies": { "glob": "^7.1.3" }, @@ -11142,6 +11554,12 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "optional": true + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -11421,6 +11839,61 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-get/node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/simple-get/node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -11875,6 +12348,50 @@ "node": ">=4" } }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "optional": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -11900,6 +12417,11 @@ "node": ">=0.8" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + }, "node_modules/tiny-warning": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", @@ -12857,6 +13379,14 @@ "node": ">=14" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -13018,6 +13548,35 @@ "resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz", "integrity": "sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw==" }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wide-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "optional": true + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -13139,7 +13698,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "devOptional": true }, "node_modules/ws": { "version": "8.16.0", diff --git a/src/frontend/package.json b/src/frontend/package.json index 338c8a541..3a6a2a8a9 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -26,6 +26,7 @@ "@tailwindcss/line-clamp": "^0.4.4", "@types/axios": "^0.14.0", "ace-builds": "^1.24.1", + "ag-grid-react": "^31.2.1", "ansi-to-html": "^0.7.2", "axios": "^1.5.0", "base64-js": "^1.5.1", @@ -35,11 +36,13 @@ "dompurify": "^3.0.5", "dotenv": "^16.4.5", "esbuild": "^0.17.19", + "file-saver": "^2.0.5", "framer-motion": "^11.0.6", "lodash": "^4.17.21", "lucide-react": "^0.331.0", "million": "^3.0.6", "moment": "^2.29.4", + "openseadragon": "^4.1.1", "playwright": "^1.42.0", "react": "^18.2.0", "react-ace": "^10.1.0", @@ -49,6 +52,7 @@ "react-icons": "^5.0.1", "react-laag": "^2.0.5", "react-markdown": "^8.0.7", + "react-pdf": "^7.7.1", "react-router-dom": "^6.15.0", "react-syntax-highlighter": "^15.5.0", "react18-json-view": "^0.2.3", diff --git a/src/frontend/src/components/ImageViewer/index.tsx b/src/frontend/src/components/ImageViewer/index.tsx new file mode 100644 index 000000000..6adda4e3e --- /dev/null +++ b/src/frontend/src/components/ImageViewer/index.tsx @@ -0,0 +1,141 @@ +import { useEffect, useRef, useState } from "react"; +import ForwardedIconComponent from "../genericIconComponent"; +import useFlowStore from "../../stores/flowStore"; +import OpenSeadragon from 'openseadragon'; +import { Separator } from "../ui/separator"; +import { saveAs } from 'file-saver' +import useAlertStore from "../../stores/alertStore"; +import { IMGViewErrorMSG, IMGViewErrorTitle } from "../../constants/constants"; + +export default function ImageViewer({image }) { + const viewerRef = useRef(null); + const [errorDownloading, setErrordownloading] = useState(false) + const setErrorList = useAlertStore(state => state.setErrorData); + const [initialMsg, setInicialMsg] = useState("Please build your flow"); + + + useEffect(() => { + try { + if (viewerRef.current) { + // Initialize OpenSeadragon viewer + const viewer = OpenSeadragon({ + element: viewerRef.current, + prefixUrl: 'https://cdnjs.cloudflare.com/ajax/libs/openseadragon/2.4.2/images/', // Optional: Set the path to OpenSeadragon images + tileSources: {type: 'image', url: image}, + defaultZoomLevel: 1, + maxZoomPixelRatio: 4, + showNavigationControl: false, + }); + const zoomInButton = document.getElementById('zoom-in-button'); + const zoomOutButton = document.getElementById('zoom-out-button'); + const homeButton = document.getElementById('home-button'); + const fullPageButton = document.getElementById('full-page-button'); + + zoomInButton!.addEventListener('click', () => viewer.viewport.zoomBy(1.2)); + zoomOutButton!.addEventListener('click', () => viewer.viewport.zoomBy(0.8)); + homeButton!.addEventListener('click', () => viewer.viewport.goHome()); + fullPageButton!.addEventListener('click', () => viewer.setFullScreen(true)); + + // Optionally, you can set additional viewer options here + + // Cleanup function + return () => { + viewer.destroy(); + zoomInButton!.removeEventListener('click', () => viewer.viewport.zoomBy(1.2)); + zoomOutButton!.removeEventListener('click', () => viewer.viewport.zoomBy(0.8)); + homeButton!.removeEventListener('click', () => viewer.viewport.goHome()); + fullPageButton!.removeEventListener('click', () => viewer.setFullScreen(true)); + }; + } + } catch (error) { + console.error('Error initializing OpenSeadragon:', error); + } + }, [image]); + + function download() { + const imageUrl = image; + // Fetch the image data + fetch(imageUrl) + .then(response => response.blob()) + .then(blob => { + // Save the image using FileSaver.js + saveAs(blob, 'image.jpg'); + }) + .catch(error => { + setErrorList({title: "There was an error downloading your image"}) + console.error('Error downloading image:', error) + }); + } + + return ( + image === "" ? ( +
+
+ + {IMGViewErrorTitle} +
+
+
+
+ {IMGViewErrorMSG} +
+
+
+
+ ) : ( + <> +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ + + +
+
+
+ + ) + ); +} \ No newline at end of file diff --git a/src/frontend/src/components/csvOutputComponent/helpers/convert-data-function.ts b/src/frontend/src/components/csvOutputComponent/helpers/convert-data-function.ts new file mode 100644 index 000000000..9c9211ac6 --- /dev/null +++ b/src/frontend/src/components/csvOutputComponent/helpers/convert-data-function.ts @@ -0,0 +1,27 @@ +export const convertCSVToData = (csvFile, csvSeparator: string) => { + const lines = csvFile.data.trim().split("\n"); + const headers = lines[0].trim().split(csvSeparator); + + + const initialRowData: any = []; + const initialColDefs = headers.map((header) => ({ + field: header.trim(), + wrapText: true, + autoHeight: true, + height: "100%", + })); + + for (let i = 1; i < lines.length; i++) { + const data = lines[i].trim().split(csvSeparator); + const rowDataEntry: any = {}; + + for (let j = 0; j < headers.length; j++) { + const value = isNaN(data[j]) ? data[j] : parseFloat(data[j]); + rowDataEntry[headers[j].trim()] = value; + } + + initialRowData.push(rowDataEntry); + } + + return { rowData: initialRowData, colDefs: initialColDefs }; +}; diff --git a/src/frontend/src/components/csvOutputComponent/index.tsx b/src/frontend/src/components/csvOutputComponent/index.tsx new file mode 100644 index 000000000..dbe527bc0 --- /dev/null +++ b/src/frontend/src/components/csvOutputComponent/index.tsx @@ -0,0 +1,182 @@ +import "ag-grid-community/styles/ag-grid.css"; // Mandatory CSS required by the grid +import "ag-grid-community/styles/ag-theme-balham.css"; // Optional Theme applied to the grid +import { AgGridReact } from "ag-grid-react"; +import { useCallback, useEffect, useMemo, useState } from "react"; +import { + CSVError, + CSVNoDataError, + CSVViewErrorTitle, +} from "../../constants/constants"; +import { useDarkStore } from "../../stores/darkStore"; +import { FlowPoolObjectType } from "../../types/chat"; +import { NodeType } from "../../types/flow"; +import ForwardedIconComponent from "../genericIconComponent"; +import Loading from "../ui/loading"; +import { convertCSVToData } from "./helpers/convert-data-function"; + +function CsvOutputComponent({ + csvNode, + flowPool, +}: { + csvNode: NodeType; + flowPool: FlowPoolObjectType; +}) { + const csvNodeArtifacts = flowPool?.data?.artifacts?.repr; + const jsonString = csvNodeArtifacts?.replace(/'/g, '"'); + let file = null; + try { + file = JSON?.parse(jsonString) || ""; + } catch (e) { + console.log("Error parsing JSON"); + } + + if (!file) { + return ( +
+
+ + {CSVViewErrorTitle} +
+
+
+
{CSVError}
+
+
+
+ ); + } + + const separator = csvNode?.data?.node?.template?.separator?.value || ","; + + const dark = useDarkStore.getState().dark; + + const [rowData, setRowData] = useState([]); + const [colDefs, setColDefs] = useState([]); + + const [status, setStatus] = useState("loading"); + var currentRowHeight: number; + var minRowHeight = 25; + const defaultColDef = useMemo(() => { + return { + width: 200, + editable: true, + filter: true, + }; + }, []); + + useEffect(() => { + setStatus("loading"); + if (file) { + const { rowData: data, colDefs: columns } = convertCSVToData( + file, + separator + ); + setRowData(data); + setColDefs(columns); + + setTimeout(() => { + setStatus("loaded"); + }, 1000); + } else { + setStatus("nodata"); + } + }, [separator]); + + const getRowHeight = useCallback(() => { + return currentRowHeight; + }, []); + + const onGridReady = useCallback((params: any) => { + minRowHeight = params.api.getSizesForCurrentTheme().rowHeight; + currentRowHeight = minRowHeight; + }, []); + + const updateRowHeight = (params: { api: any }) => { + const bodyViewport = document.querySelector(".ag-body-viewport"); + if (!bodyViewport) { + return; + } + var gridHeight = bodyViewport.clientHeight; + var renderedRowCount = params.api.getDisplayedRowCount(); + + if (renderedRowCount * minRowHeight >= gridHeight) { + if (currentRowHeight !== minRowHeight) { + currentRowHeight = minRowHeight; + params.api.resetRowHeights(); + } + } else { + currentRowHeight = Math.floor(gridHeight / renderedRowCount); + params.api.resetRowHeights(); + } + }; + + const onFirstDataRendered = useCallback( + (params: any) => { + updateRowHeight(params); + }, + [updateRowHeight] + ); + + const onGridSizeChanged = useCallback( + (params: any) => { + updateRowHeight(params); + }, + [updateRowHeight] + ); + + return ( +
+ {status === "nodata" && ( +
+
+ + {CSVViewErrorTitle} +
+
+
+
{CSVNoDataError}
+
+
+
+ )} + {status === "error" && ( +
+
+ + {CSVViewErrorTitle} +
+
+
+
{CSVError}
+
+
+
+ )} + + {status === "loaded" && ( +
+ +
+ )} + {status === "loading" && ( +
+ +
+ )} +
+ ); +} + +export default CsvOutputComponent; diff --git a/src/frontend/src/components/pdfViewer/Error/index.tsx b/src/frontend/src/components/pdfViewer/Error/index.tsx new file mode 100644 index 000000000..76c35bcd0 --- /dev/null +++ b/src/frontend/src/components/pdfViewer/Error/index.tsx @@ -0,0 +1,23 @@ +import { CHAT_FIRST_INITIAL_TEXT, CHAT_SECOND_INITIAL_TEXT, PDFCheckFlow, PDFLoadErrorTitle } from "../../../constants/constants"; +import IconComponent from "../../genericIconComponent"; + + +export default function Error(): JSX.Element { + return ( +
+
+ + + {PDFLoadErrorTitle} + +
+
+ + {PDFCheckFlow}{" "} + +
+
+ +
+ ); +} \ No newline at end of file diff --git a/src/frontend/src/components/pdfViewer/index.tsx b/src/frontend/src/components/pdfViewer/index.tsx new file mode 100644 index 000000000..725dec395 --- /dev/null +++ b/src/frontend/src/components/pdfViewer/index.tsx @@ -0,0 +1,155 @@ +import { useEffect, useRef, useState } from "react"; +import { Document, Page, pdfjs } from "react-pdf"; +import "react-pdf/dist/esm/Page/AnnotationLayer.css"; +import "react-pdf/dist/esm/Page/TextLayer.css"; +import IconComponent from "../genericIconComponent"; +import Loading from "../ui/loading"; +import Error from "./Error"; +import NoDataPdf from "./noData"; + +pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`; + +export default function PdfViewer({ pdf }: { pdf: string }): JSX.Element { + const [numPages, setNumPages] = useState(-1); + const [pageNumber, setPageNumber] = useState(1); + const [scale, setScale] = useState(1); + const [width, setWidth] = useState(undefined); + const [showControl, setShowControl] = useState(false); + const container = useRef(null); + + //shortcuts to change page + useEffect(() => { + function handleKeyDown(event: KeyboardEvent) { + if (event.key === "ArrowLeft") { + if (pageNumber > 1) previousPage(); + } else if (event.key === "ArrowRight") { + if (pageNumber < numPages) nextPage(); + } + } + document.addEventListener("keydown", handleKeyDown); + return () => { + document.removeEventListener("keydown", handleKeyDown); + }; + }, [pageNumber]); + + function onDocumentLoadSuccess({ numPages }) { + setNumPages(numPages); + setPageNumber(1); + } + + function changePage(offset) { + setPageNumber((prevPageNumber) => prevPageNumber + offset); + } + + function previousPage() { + changePage(-1); + } + + function nextPage() { + changePage(1); + } + + //set handle scale in % to real number + function handleScaleChange(e) { + //check if e is a number + if (isNaN(e) || e < 0.1) return; + // round to 2 decimal places + e = Math.round(e * 10) / 10; + + setScale(e); + } + + function zoomIn() { + handleScaleChange(scale + 0.1); + } + function zoomOut() { + if (scale > 0.1) handleScaleChange(scale - 0.1); + } + + function handlePageLoad(page) { + if (!container.current) return; + const containerWidth = container.current.clientWidth; + const pageWidth = page.width; + if (containerWidth > pageWidth) { + setWidth(containerWidth - 10); + } + } + + return ( +
setShowControl(true)} + onMouseLeave={(_) => setShowControl(false)} + className="flex h-full w-full flex-col items-center justify-end overflow-clip rounded-lg border border-border" + > +
+ + +
+ } + onLoadSuccess={onDocumentLoadSuccess} + file={pdf} + noData={} + error={} + className="h-full w-full" + > + + +
+
0 ? "" : " hidden") + } + > +
+ +

+ {pageNumber || (numPages ? 1 : "--")}/{numPages || "--"} +

+ +

|

+ + handleScaleChange(e.target.value)} + value={scale} + /> + +
+
+
+ ); +} diff --git a/src/frontend/src/components/pdfViewer/noData/index.tsx b/src/frontend/src/components/pdfViewer/noData/index.tsx new file mode 100644 index 000000000..b5edee0bb --- /dev/null +++ b/src/frontend/src/components/pdfViewer/noData/index.tsx @@ -0,0 +1,17 @@ +import { PDFErrorTitle, PDFLoadError } from "../../../constants/constants"; + +export default function NoDataPdf(): JSX.Element { + return ( +
+
+ + 📄 {PDFErrorTitle} + +
+
+ {PDFLoadError} +
+
+
+ ); +} diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index c8d7626ca..49483875c 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -161,6 +161,29 @@ export const IMPORT_DIALOG_SUBTITLE = */ export const TOOLTIP_EMPTY = "No compatible components found."; +export const CSVViewErrorTitle = "CSV output"; + +export const CSVNoDataError = "No data available"; + +export const PDFViewConstant = "Expand the ouptut to see the PDF"; + +export const CSVError = "Error loading CSV"; + +export const PDFLoadErrorTitle = "Error loading PDF"; + +export const PDFCheckFlow = "Please check your flow and try again"; + +export const PDFErrorTitle = "PDF Output"; + +export const PDFLoadError = "Run the flow to see the pdf"; + +export const IMGViewConstant = "Expand the view to see the image"; + +export const IMGViewErrorMSG = + "Run the flow or inform a valid url to see your image"; + +export const IMGViewErrorTitle = "Image output"; + /** * The base text for subtitle of code dialog * @constant @@ -688,8 +711,14 @@ export const LANGFLOW_SUPPORTED_TYPES = new Set([ export const priorityFields = new Set(["code", "template"]); -export const INPUT_TYPES = new Set(["ChatInput", "TextInput"]); -export const OUTPUT_TYPES = new Set(["ChatOutput", "TextOutput"]); +export const INPUT_TYPES = new Set(["ChatInput", "TextInput", "KeyPairInput"]); +export const OUTPUT_TYPES = new Set([ + "ChatOutput", + "TextOutput", + "PDFOutput", + "ImageOutput", + "CSVOutput", +]); export const CHAT_FIRST_INITIAL_TEXT = "Start a conversation and click the agent's thoughts"; diff --git a/src/frontend/src/modals/IOModal/components/IOFieldView/index.tsx b/src/frontend/src/modals/IOModal/components/IOFieldView/index.tsx index 37c9461b5..dd02d19ca 100644 --- a/src/frontend/src/modals/IOModal/components/IOFieldView/index.tsx +++ b/src/frontend/src/modals/IOModal/components/IOFieldView/index.tsx @@ -1,5 +1,17 @@ import { cloneDeep } from "lodash"; +import ImageViewer from "../../../../components/ImageViewer"; +import CsvOutputComponent from "../../../../components/csvOutputComponent"; +import PdfViewer from "../../../../components/pdfViewer"; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectTrigger, + SelectValue, +} from "../../../../components/ui/select"; import { Textarea } from "../../../../components/ui/textarea"; +import { PDFViewConstant } from "../../../../constants/constants"; import { InputOutput } from "../../../../constants/enums"; import useFlowStore from "../../../../stores/flowStore"; import { IOFieldViewProps } from "../../../../types/components"; @@ -15,6 +27,19 @@ export default function IOFieldView({ const setNode = useFlowStore((state) => state.setNode); const flowPool = useFlowStore((state) => state.flowPool); const node = nodes.find((node) => node.id === fieldId); + const flowPoolNode = (flowPool[node!.id] ?? [])[ + (flowPool[node!.id]?.length ?? 1) - 1 + ]; + const handleChangeSelect = (e) => { + if (node) { + let newNode = cloneDeep(node); + if (newNode.data.node.template.separator) { + newNode.data.node.template.separator.value = e; + setNode(newNode.id, newNode); + } + } + }; + function handleOutputType() { if (!node) return <>"No node found!"; switch (type) { @@ -91,6 +116,58 @@ export default function IOFieldView({ readOnly /> ); + case "PDFOutput": + return left ? ( +
{PDFViewConstant}
+ ) : ( + + ); + case "CSVOutput": + return left ? ( + <> +
+ Expand the ouptut to see the CSV +
+
+ CSV separator + +
+ + ) : ( + <> + + + ); + case "ImageOutput": + return left ? ( +
Expand the view to see the image
+ ) : ( + + ); default: return (