From a7113384e8d53ce6261eebf80cb42cf2c1a7d491 Mon Sep 17 00:00:00 2001
From: Geomitron <22552797+Geomitron@users.noreply.github.com>
Date: Sun, 22 Dec 2024 18:35:43 -0600
Subject: [PATCH] Add "Tools" tab with chart issue scanner
---
package.json | 1 +
pnpm-lock.yaml | 231 +++++++++++++++++
src-angular/app/app-routing.module.ts | 2 +
.../components/toolbar/toolbar.component.html | 1 +
.../app/components/tools/tools.component.html | 62 +++++
.../app/components/tools/tools.component.ts | 77 ++++++
.../app/core/services/settings.service.ts | 14 +
src-electron/IpcHandler.ts | 2 +
src-electron/ipc/SettingsHandler.ipc.ts | 1 +
src-electron/ipc/issue-scan/ExcelBuilder.ts | 240 ++++++++++++++++++
.../ipc/issue-scan/IssueScanHandler.ipc.ts | 183 +++++++++++++
src-electron/preload.ts | 2 +
src-shared/Settings.ts | 30 ++-
src-shared/UtilFunctions.ts | 31 +++
src-shared/interfaces/ipc.interface.ts | 2 +
15 files changed, 866 insertions(+), 13 deletions(-)
create mode 100644 src-angular/app/components/tools/tools.component.html
create mode 100644 src-angular/app/components/tools/tools.component.ts
create mode 100644 src-electron/ipc/issue-scan/ExcelBuilder.ts
create mode 100644 src-electron/ipc/issue-scan/IssueScanHandler.ipc.ts
diff --git a/package.json b/package.json
index d1f6f96..b43c47b 100644
--- a/package.json
+++ b/package.json
@@ -42,6 +42,7 @@
"electron-updater": "6.2.1",
"electron-window-state": "5.0.3",
"eventemitter3": "5.0.1",
+ "exceljs": "^4.4.0",
"fs-extra": "11.2.0",
"lodash": "4.17.21",
"parse-sng": "4.0.3",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index bea048d..1cdfeb2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -59,6 +59,9 @@ importers:
eventemitter3:
specifier: 5.0.1
version: 5.0.1
+ exceljs:
+ specifier: ^4.4.0
+ version: 4.4.0
fs-extra:
specifier: 11.2.0
version: 11.2.0
@@ -810,6 +813,12 @@ packages:
resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ '@fast-csv/format@4.3.5':
+ resolution: {integrity: sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==}
+
+ '@fast-csv/parse@4.3.6':
+ resolution: {integrity: sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==}
+
'@humanwhocodes/config-array@0.11.14':
resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
engines: {node: '>=10.10.0'}
@@ -1238,6 +1247,9 @@ packages:
'@types/ms@0.7.34':
resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==}
+ '@types/node@14.18.63':
+ resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==}
+
'@types/node@18.16.0':
resolution: {integrity: sha512-BsAaKhB+7X+H4GnSjGhJG9Qi8Tw+inU9nJDwmD5CgOmBLEI6ArdhikpLX7DjbjDRDTbqZzU2LSQNZg8WGPiSZQ==}
@@ -1576,6 +1588,10 @@ packages:
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+ big-integer@1.6.52:
+ resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==}
+ engines: {node: '>=0.6'}
+
binary-extensions@2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
@@ -1584,12 +1600,18 @@ packages:
resolution: {integrity: sha512-5ATpz/uPDgq5GgEDxTB4ouXCde7q2lqAQlSdBRQVl/AJnxmQmhIfyxJx+0MGu//D5rHQifkfGbWWlaysG0o9NA==}
engines: {node: '>=12'}
+ binary@0.3.0:
+ resolution: {integrity: sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==}
+
bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
bluebird-lst@1.0.9:
resolution: {integrity: sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==}
+ bluebird@3.4.7:
+ resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==}
+
bluebird@3.7.2:
resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
@@ -1630,9 +1652,17 @@ packages:
buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
+ buffer-indexof-polyfill@1.0.2:
+ resolution: {integrity: sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==}
+ engines: {node: '>=0.10'}
+
buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
+ buffers@0.1.1:
+ resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==}
+ engines: {node: '>=0.2.0'}
+
builder-util-runtime@9.2.4:
resolution: {integrity: sha512-upp+biKpN/XZMLim7aguUyW8s0FUpDvOtK6sbanMFDAMBzpHDqdhgVYm6zc9HJ6nWo7u2Lxk60i2M6Jd3aiNrA==}
engines: {node: '>=12.0.0'}
@@ -1670,6 +1700,9 @@ packages:
caniuse-lite@1.0.30001640:
resolution: {integrity: sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA==}
+ chainsaw@0.1.0:
+ resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==}
+
chalk@1.1.3:
resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==}
engines: {node: '>=0.10.0'}
@@ -1984,6 +2017,9 @@ packages:
resolution: {tarball: https://codeload.github.com/corbanbrook/dsp.js/tar.gz/219600bb0346ee9a00686c9875c81123e2d8780e}
version: 1.0.0
+ duplexer2@0.1.4:
+ resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==}
+
duplexer@0.1.2:
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
@@ -2225,6 +2261,10 @@ packages:
eventemitter3@5.0.1:
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
+ exceljs@4.4.0:
+ resolution: {integrity: sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==}
+ engines: {node: '>=8.3.0'}
+
exifreader@4.23.3:
resolution: {integrity: sha512-/Ii4jiNp/5BXdKOiWXZYrWmZFn/ANu3bMVGO7GFQufao5M52/fK2OsAPMH34PL4S79z1eZBzAoaYyBXit0zzVA==}
@@ -2244,6 +2284,10 @@ packages:
resolution: {integrity: sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==}
engines: {'0': node >=0.6.0}
+ fast-csv@4.3.6:
+ resolution: {integrity: sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==}
+ engines: {node: '>=10.0.0'}
+
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
@@ -2364,6 +2408,11 @@ packages:
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
+ fstream@1.0.12:
+ resolution: {integrity: sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==}
+ engines: {node: '>=0.6'}
+ deprecated: This package is no longer supported.
+
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
@@ -2546,6 +2595,9 @@ packages:
resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
engines: {node: '>= 4'}
+ immediate@3.0.6:
+ resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
+
immutable@4.3.4:
resolution: {integrity: sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==}
@@ -2791,6 +2843,9 @@ packages:
resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==}
engines: {'0': node >= 0.2.0}
+ jszip@3.10.1:
+ resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==}
+
keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
@@ -2805,6 +2860,9 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
+ lie@3.3.0:
+ resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
+
lilconfig@2.1.0:
resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
engines: {node: '>=10'}
@@ -2820,6 +2878,9 @@ packages:
resolution: {integrity: sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ listenercount@1.0.1:
+ resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==}
+
lmdb@3.0.8:
resolution: {integrity: sha512-9rp8JT4jPhCRJUL7vRARa2N06OLSYzLwQsEkhC6Qu5XbcLyM/XBLMzDlgS/K7l7c5CdURLdDk9uE+hPFIogHTQ==}
hasBin: true
@@ -2843,18 +2904,36 @@ packages:
lodash.flatten@4.4.0:
resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==}
+ lodash.groupby@4.6.0:
+ resolution: {integrity: sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==}
+
+ lodash.isboolean@3.0.3:
+ resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
+
lodash.isequal@4.5.0:
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
+ lodash.isfunction@3.0.9:
+ resolution: {integrity: sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==}
+
+ lodash.isnil@4.0.0:
+ resolution: {integrity: sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==}
+
lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
+ lodash.isundefined@3.0.1:
+ resolution: {integrity: sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==}
+
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
lodash.union@4.6.0:
resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==}
+ lodash.uniq@4.5.0:
+ resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==}
+
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
@@ -3223,6 +3302,9 @@ packages:
engines: {node: ^16.14.0 || >=18.0.0}
hasBin: true
+ pako@1.0.11:
+ resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
+
parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
@@ -3489,6 +3571,11 @@ packages:
rfc4648@1.5.3:
resolution: {integrity: sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ==}
+ rimraf@2.7.1:
+ resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
+ deprecated: Rimraf versions prior to v4 are no longer supported
+ hasBin: true
+
rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
deprecated: Rimraf versions prior to v4 are no longer supported
@@ -3540,6 +3627,10 @@ packages:
sax@1.3.0:
resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==}
+ saxes@5.0.1:
+ resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==}
+ engines: {node: '>=10'}
+
scan-chart@4.1.4:
resolution: {integrity: sha512-LzFMfPxLgT7X5TCYK5Xkags3XVu3V7JAoDg7Te0A5GkSivwKA4fnwMRpdtRLiThlnspIAO2L/+lrysz1pIagmg==}
@@ -3571,6 +3662,9 @@ packages:
resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==}
engines: {node: '>= 0.4'}
+ setimmediate@1.0.5:
+ resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
+
shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
@@ -3828,6 +3922,9 @@ packages:
resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==}
hasBin: true
+ traverse@0.3.9:
+ resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==}
+
tree-kill@1.2.2:
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
hasBin: true
@@ -3927,6 +4024,9 @@ packages:
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
+ unzipper@0.10.14:
+ resolution: {integrity: sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==}
+
update-browserslist-db@1.1.0:
resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==}
hasBin: true
@@ -3942,6 +4042,10 @@ packages:
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+ uuid@8.3.2:
+ resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
+ hasBin: true
+
validate-npm-package-license@3.0.4:
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
@@ -4040,6 +4144,9 @@ packages:
resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==}
engines: {node: '>=8.0'}
+ xmlchars@2.2.0:
+ resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+
y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
@@ -4735,6 +4842,25 @@ snapshots:
'@eslint/js@8.57.0': {}
+ '@fast-csv/format@4.3.5':
+ dependencies:
+ '@types/node': 14.18.63
+ lodash.escaperegexp: 4.1.2
+ lodash.isboolean: 3.0.3
+ lodash.isequal: 4.5.0
+ lodash.isfunction: 3.0.9
+ lodash.isnil: 4.0.0
+
+ '@fast-csv/parse@4.3.6':
+ dependencies:
+ '@types/node': 14.18.63
+ lodash.escaperegexp: 4.1.2
+ lodash.groupby: 4.6.0
+ lodash.isfunction: 3.0.9
+ lodash.isnil: 4.0.0
+ lodash.isundefined: 3.0.1
+ lodash.uniq: 4.5.0
+
'@humanwhocodes/config-array@0.11.14':
dependencies:
'@humanwhocodes/object-schema': 2.0.3
@@ -5131,6 +5257,8 @@ snapshots:
'@types/ms@0.7.34': {}
+ '@types/node@14.18.63': {}
+
'@types/node@18.16.0': {}
'@types/node@20.14.10':
@@ -5553,10 +5681,17 @@ snapshots:
base64-js@1.5.1: {}
+ big-integer@1.6.52: {}
+
binary-extensions@2.2.0: {}
binary-parser@2.2.1: {}
+ binary@0.3.0:
+ dependencies:
+ buffers: 0.1.1
+ chainsaw: 0.1.0
+
bl@4.1.0:
dependencies:
buffer: 5.7.1
@@ -5567,6 +5702,8 @@ snapshots:
dependencies:
bluebird: 3.7.2
+ bluebird@3.4.7: {}
+
bluebird@3.7.2: {}
boolbase@1.0.0: {}
@@ -5604,11 +5741,15 @@ snapshots:
buffer-from@1.1.2: {}
+ buffer-indexof-polyfill@1.0.2: {}
+
buffer@5.7.1:
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
+ buffers@0.1.1: {}
+
builder-util-runtime@9.2.4:
dependencies:
debug: 4.3.5(supports-color@5.5.0)
@@ -5682,6 +5823,10 @@ snapshots:
caniuse-lite@1.0.30001640: {}
+ chainsaw@0.1.0:
+ dependencies:
+ traverse: 0.3.9
+
chalk@1.1.3:
dependencies:
ansi-styles: 2.2.1
@@ -6008,6 +6153,10 @@ snapshots:
dsp.js@https://codeload.github.com/corbanbrook/dsp.js/tar.gz/219600bb0346ee9a00686c9875c81123e2d8780e: {}
+ duplexer2@0.1.4:
+ dependencies:
+ readable-stream: 2.3.8
+
duplexer@0.1.2: {}
eastasianwidth@0.2.0: {}
@@ -6403,6 +6552,18 @@ snapshots:
eventemitter3@5.0.1: {}
+ exceljs@4.4.0:
+ dependencies:
+ archiver: 5.3.2
+ dayjs: 1.11.11
+ fast-csv: 4.3.6
+ jszip: 3.10.1
+ readable-stream: 3.6.2
+ saxes: 5.0.1
+ tmp: 0.2.1
+ unzipper: 0.10.14
+ uuid: 8.3.2
+
exifreader@4.23.3:
optionalDependencies:
'@xmldom/xmldom': 0.8.10
@@ -6428,6 +6589,11 @@ snapshots:
extsprintf@1.4.1:
optional: true
+ fast-csv@4.3.6:
+ dependencies:
+ '@fast-csv/format': 4.3.5
+ '@fast-csv/parse': 4.3.6
+
fast-deep-equal@3.1.3: {}
fast-diff@1.3.0: {}
@@ -6553,6 +6719,13 @@ snapshots:
fsevents@2.3.3:
optional: true
+ fstream@1.0.12:
+ dependencies:
+ graceful-fs: 4.2.11
+ inherits: 2.0.4
+ mkdirp: 0.5.6
+ rimraf: 2.7.1
+
function-bind@1.1.2: {}
function.prototype.name@1.1.6:
@@ -6773,6 +6946,8 @@ snapshots:
ignore@5.3.1: {}
+ immediate@3.0.6: {}
+
immutable@4.3.4: {}
import-fresh@3.3.0:
@@ -6995,6 +7170,13 @@ snapshots:
jsonparse@1.3.1: {}
+ jszip@3.10.1:
+ dependencies:
+ lie: 3.3.0
+ pako: 1.0.11
+ readable-stream: 2.3.8
+ setimmediate: 1.0.5
+
keyv@4.5.4:
dependencies:
json-buffer: 3.0.1
@@ -7010,6 +7192,10 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
+ lie@3.3.0:
+ dependencies:
+ immediate: 3.0.6
+
lilconfig@2.1.0: {}
lilconfig@3.0.0: {}
@@ -7018,6 +7204,8 @@ snapshots:
lines-and-columns@2.0.4: {}
+ listenercount@1.0.1: {}
+
lmdb@3.0.8:
dependencies:
msgpackr: 1.10.2
@@ -7047,14 +7235,26 @@ snapshots:
lodash.flatten@4.4.0: {}
+ lodash.groupby@4.6.0: {}
+
+ lodash.isboolean@3.0.3: {}
+
lodash.isequal@4.5.0: {}
+ lodash.isfunction@3.0.9: {}
+
+ lodash.isnil@4.0.0: {}
+
lodash.isplainobject@4.0.6: {}
+ lodash.isundefined@3.0.1: {}
+
lodash.merge@4.6.2: {}
lodash.union@4.6.0: {}
+ lodash.uniq@4.5.0: {}
+
lodash@4.17.21: {}
log-symbols@4.1.0:
@@ -7526,6 +7726,8 @@ snapshots:
- bluebird
- supports-color
+ pako@1.0.11: {}
+
parent-module@1.0.1:
dependencies:
callsites: 3.1.0
@@ -7771,6 +7973,10 @@ snapshots:
rfc4648@1.5.3: {}
+ rimraf@2.7.1:
+ dependencies:
+ glob: 7.2.3
+
rimraf@3.0.2:
dependencies:
glob: 7.2.3
@@ -7848,6 +8054,10 @@ snapshots:
sax@1.3.0: {}
+ saxes@5.0.1:
+ dependencies:
+ xmlchars: 2.2.0
+
scan-chart@4.1.4:
dependencies:
'@noble/hashes': 1.4.0
@@ -7892,6 +8102,8 @@ snapshots:
functions-have-names: 1.2.3
has-property-descriptors: 1.0.2
+ setimmediate@1.0.5: {}
+
shebang-command@2.0.0:
dependencies:
shebang-regex: 3.0.0
@@ -8193,6 +8405,8 @@ snapshots:
dependencies:
nopt: 1.0.10
+ traverse@0.3.9: {}
+
tree-kill@1.2.2: {}
truncate-utf8-bytes@1.0.2:
@@ -8295,6 +8509,19 @@ snapshots:
universalify@2.0.1: {}
+ unzipper@0.10.14:
+ dependencies:
+ big-integer: 1.6.52
+ binary: 0.3.0
+ bluebird: 3.4.7
+ buffer-indexof-polyfill: 1.0.2
+ duplexer2: 0.1.4
+ fstream: 1.0.12
+ graceful-fs: 4.2.11
+ listenercount: 1.0.1
+ readable-stream: 2.3.8
+ setimmediate: 1.0.5
+
update-browserslist-db@1.1.0(browserslist@4.23.2):
dependencies:
browserslist: 4.23.2
@@ -8309,6 +8536,8 @@ snapshots:
util-deprecate@1.0.2: {}
+ uuid@8.3.2: {}
+
validate-npm-package-license@3.0.4:
dependencies:
spdx-correct: 3.2.0
@@ -8411,6 +8640,8 @@ snapshots:
xmlbuilder@15.1.1: {}
+ xmlchars@2.2.0: {}
+
y18n@5.0.8: {}
yallist@3.1.1: {}
diff --git a/src-angular/app/app-routing.module.ts b/src-angular/app/app-routing.module.ts
index 7a9f467..c33b5cf 100644
--- a/src-angular/app/app-routing.module.ts
+++ b/src-angular/app/app-routing.module.ts
@@ -3,11 +3,13 @@ import { RouteReuseStrategy, RouterModule, Routes } from '@angular/router'
import { BrowseComponent } from './components/browse/browse.component'
import { SettingsComponent } from './components/settings/settings.component'
+import { ToolsComponent } from './components/tools/tools.component'
import { TabPersistStrategy } from './core/tab-persist.strategy'
const routes: Routes = [
{ path: 'browse', component: BrowseComponent, data: { shouldReuse: true } },
{ path: 'library', redirectTo: '/browse' },
+ { path: 'tools', component: ToolsComponent, data: { shouldReuse: true } },
{ path: 'settings', component: SettingsComponent, data: { shouldReuse: true } },
{ path: 'about', redirectTo: '/browse' },
{ path: '**', redirectTo: '/browse' },
diff --git a/src-angular/app/components/toolbar/toolbar.component.html b/src-angular/app/components/toolbar/toolbar.component.html
index dd20c41..b70ab3f 100644
--- a/src-angular/app/components/toolbar/toolbar.component.html
+++ b/src-angular/app/components/toolbar/toolbar.component.html
@@ -1,6 +1,7 @@
+