aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreleanor-park <eleanor_park@brown.edu>2024-09-22 15:40:29 -0400
committereleanor-park <eleanor_park@brown.edu>2024-09-22 15:40:29 -0400
commit6d0cec80757dcdb07434d7788dd2eb97c2ce4b7c (patch)
tree58bc45587534b17a5bb340e8e5bafc47a749f14f
parent692076b1356309111c4f2cb69cbdbf4be1a825bd (diff)
parent97c150a2b53ccb27921125d55c9cbf42abf3c588 (diff)
Merge branch 'eleanor-gptdraw' of https://github.com/brown-dash/Dash-Web into eleanor-gptdraw
-rw-r--r--.gitignore2
-rw-r--r--eslint.config.mjs5
-rw-r--r--package-lock.json2639
-rw-r--r--package.json35
-rw-r--r--src/ClientUtils.ts18
-rw-r--r--src/client/Network.ts2
-rw-r--r--src/client/apis/gpt/GPT.ts45
-rw-r--r--src/client/documents/DocUtils.ts3
-rw-r--r--src/client/documents/DocumentTypes.ts1
-rw-r--r--src/client/documents/Documents.ts22
-rw-r--r--src/client/util/CurrentUserUtils.ts110
-rw-r--r--src/client/util/DocumentManager.ts4
-rw-r--r--src/client/util/DragManager.ts5
-rw-r--r--src/client/util/node_modules/type_decls.d (renamed from src/typings/type_decls.d)0
-rw-r--r--src/client/util/request-image-size.ts9
-rw-r--r--src/client/views/DashboardView.tsx2
-rw-r--r--src/client/views/DocumentButtonBar.scss9
-rw-r--r--src/client/views/DocumentButtonBar.tsx38
-rw-r--r--src/client/views/DocumentDecorations.scss7
-rw-r--r--src/client/views/DocumentDecorations.tsx24
-rw-r--r--src/client/views/FilterPanel.scss92
-rw-r--r--src/client/views/FilterPanel.tsx255
-rw-r--r--src/client/views/MainView.tsx12
-rw-r--r--src/client/views/PropertiesButtons.tsx20
-rw-r--r--src/client/views/PropertiesView.tsx4
-rw-r--r--src/client/views/SidebarAnnos.tsx1
-rw-r--r--src/client/views/StyleProvider.tsx7
-rw-r--r--src/client/views/TagsView.tsx179
-rw-r--r--src/client/views/collections/CollectionCalendarView.tsx5
-rw-r--r--src/client/views/collections/CollectionCardDeckView.scss54
-rw-r--r--src/client/views/collections/CollectionCardDeckView.tsx506
-rw-r--r--src/client/views/collections/CollectionCarousel3DView.tsx1
-rw-r--r--src/client/views/collections/CollectionCarouselView.scss15
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx232
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx3
-rw-r--r--src/client/views/collections/CollectionNoteTakingView.tsx1
-rw-r--r--src/client/views/collections/CollectionStackingView.scss7
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx65
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx26
-rw-r--r--src/client/views/collections/CollectionSubView.tsx6
-rw-r--r--src/client/views/collections/CollectionView.tsx4
-rw-r--r--src/client/views/collections/TabDocView.tsx175
-rw-r--r--src/client/views/collections/TreeView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx46
-rw-r--r--src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx3
-rw-r--r--src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx4
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx4
-rw-r--r--src/client/views/collections/collectionGrid/CollectionGridView.tsx17
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss1
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss1
-rw-r--r--src/client/views/global/globalScripts.ts203
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx7
-rw-r--r--src/client/views/nodes/DocumentView.tsx5
-rw-r--r--src/client/views/nodes/FieldView.tsx5
-rw-r--r--src/client/views/nodes/FontIconBox/FontIconBox.tsx23
-rw-r--r--src/client/views/nodes/IconTagBox.scss26
-rw-r--r--src/client/views/nodes/IconTagBox.tsx92
-rw-r--r--src/client/views/nodes/ImageBox.tsx17
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx2
-rw-r--r--src/client/views/nodes/PDFBox.tsx4
-rw-r--r--src/client/views/nodes/calendarBox/CalendarBox.scss25
-rw-r--r--src/client/views/nodes/calendarBox/CalendarBox.tsx258
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx6
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts4
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.scss92
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.tsx375
-rw-r--r--src/client/views/search/FaceRecognitionHandler.tsx9
-rw-r--r--src/fields/Doc.ts8
-rw-r--r--src/server/ApiManagers/SearchManager.ts200
-rw-r--r--src/server/ApiManagers/UploadManager.ts53
-rw-r--r--src/server/DashUploadUtils.ts94
-rw-r--r--src/server/index.ts2
72 files changed, 3779 insertions, 2459 deletions
diff --git a/.gitignore b/.gitignore
index 6a1963b4e..26c504059 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-node_modules
+/node_modules
dist/
.DS_Store
.env
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 619966f20..aebdc20d0 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -36,6 +36,7 @@ export default [
'no-multi-assign': 'off',
'no-underscore-dangle': 'off',
'no-nested-ternary': 'off',
+ 'no-param-reassign': 'error',
'lines-between-class-members': 'off',
'no-shadow': 'off',
'@typescript-eslint/no-shadow': 'warn',
@@ -47,9 +48,9 @@ export default [
'no-return-assign': 'error',
'no-await-in-loop': 'error',
'no-loop-func': 'error',
- 'no-cond-assign': 'error',
+ '@typescript-eslint/no-cond-assign': 'error',
'no-use-before-define': 'error',
- 'no-explicit-any': 'error',
+ '@typescript-eslint/no-explicit-any': 'error',
'no-restricted-globals': ['error', 'event'],
},
},
diff --git a/package-lock.json b/package-lock.json
index c4d69bbcf..a393ff5dc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,12 +22,13 @@
"@fortawesome/free-regular-svg-icons": "^6.5.1",
"@fortawesome/free-solid-svg-icons": "^6.5.1",
"@fortawesome/react-fontawesome": "^0.2.0",
- "@fullcalendar/core": "^6.1.10",
+ "@fullcalendar/core": "^6.1.15",
"@fullcalendar/daygrid": "^6.1.10",
"@fullcalendar/multimonth": "^6.1.10",
+ "@fullcalendar/timegrid": "^6.1.15",
"@internationalized/date": "^3.5.0",
- "@mui/icons-material": "^5.14.19",
- "@mui/material": "^5.14.19",
+ "@mui/icons-material": "^6.0.1",
+ "@mui/material": "^6.0.1",
"@octokit/core": "^6.0.1",
"@react-google-maps/api": "^2.19.2",
"@react-spring/web": "^9.7.3",
@@ -50,10 +51,11 @@
"@types/reveal": "^4.2.0",
"@types/supercluster": "^7.1.3",
"@types/textfit": "^2.4.4",
- "@types/web": "^0.0.157",
+ "@types/web": "^0.0.163",
"@types/webpack-hot-middleware": "^2.25.9",
"@webscopeio/react-textarea-autocomplete": "^4.9.2",
"adm-zip": "^0.5.10",
+ "any-base": "^1.1.0",
"archiver": "^7.0.1",
"async": "^3.2.5",
"axios": "^1.6.2",
@@ -68,7 +70,7 @@
"body-parser": "^1.20.2",
"bootstrap": "^5.3.2",
"brotli": "^1.3.3",
- "browndash-components": "^0.1.45",
+ "browndash-components": "^0.1.47",
"browser-assert": "^1.2.1",
"bson": "^6.2.0",
"canvas": "^2.11.2",
@@ -92,7 +94,7 @@
"D": "^1.0.0",
"d3": "^7.8.5",
"depcheck": "^1.4.7",
- "dotenv": "^16.3.1",
+ "dotenv": "^16.4.5",
"eslint-webpack-plugin": "^4.1.0",
"exif": "^0.6.0",
"exifr": "^7.1.3",
@@ -107,16 +109,17 @@
"file-saver": "^2.0.5",
"find-in-files": "^0.5.0",
"fit-curve": "^0.2.0",
- "flexlayout-react": "^0.7.15",
+ "flexlayout-react": "^0.8.0",
"fluent-ffmpeg": "^2.1.2",
"forever-agent": "^0.6.1",
"fork-ts-checker-webpack-plugin": "^9.0.2",
"form-data": "^4.0.0",
"formidable": "3.5.1",
+ "fullcalendar": "^6.1.15",
"function-plot": "^1.23.3",
"golden-layout": "^2.6.0",
"google-auth-library": "^9.4.1",
- "googleapis": "^142.0.0",
+ "googleapis": "^144.0.0",
"googlephotos": "^0.3.5",
"got": "^14.0.0",
"howler": "^2.2.4",
@@ -131,8 +134,9 @@
"image-data-uri": "^2.0.1",
"image-size": "^1.0.2",
"image-size-stream": "^1.1.0",
+ "install": "^0.13.0",
"is-plain-obj": "^4.1.0",
- "jimp": "^0.22.10",
+ "jimp": "^1.0.4",
"jpeg-autorotate": "^9.0.0",
"jquery": "^3.7.1",
"js-datepicker": "^5.18.2",
@@ -155,7 +159,7 @@
"node-stream-zip": "^1.15.0",
"nodemailer": "^6.9.7",
"nodemon": "^3.0.2",
- "npm": "^10.2.5",
+ "npm": "^10.8.1",
"openai": "^4.26.0",
"p-limit": "^6.1.0",
"passport": "^0.7.0",
@@ -189,6 +193,7 @@
"react-compound-slider": "^3.4.0",
"react-datepicker": "^7.3.0",
"react-dom": "^18.2.0",
+ "react-draggable": "^4.4.6",
"react-grid-layout": "^1.4.4",
"react-icons": "^5.0.1",
"react-jsx-parser": "^2.0.0",
@@ -226,7 +231,7 @@
"svgson": "^5.3.1",
"textarea-caret": "^3.1.0",
"textfit": "^2.4.0",
- "tough-cookie": "^4.1.3",
+ "tough-cookie": "^5.0.0",
"tslint": "^6.1.3",
"tslint-loader": "^3.5.4",
"typescript": "^5.3.3",
@@ -249,7 +254,7 @@
"xregexp": "^5.1.1"
},
"devDependencies": {
- "@eslint/js": "^9.9.1",
+ "@eslint/js": "^9.10.0",
"@types/adm-zip": "^0.5.5",
"@types/animejs": "^3.1.12",
"@types/archiver": "^6.0.2",
@@ -298,8 +303,8 @@
"@types/youtube": "^0.1.0",
"chai": "^5.0.0",
"cross-env": "^7.0.3",
- "eslint": "^9.9.1",
- "eslint-plugin-react": "^7.35.0",
+ "eslint": "^9.10.0",
+ "eslint-plugin-react": "^7.36.1",
"globals": "^15.9.0",
"jsdom": "^25.0.0",
"mocha": "^10.2.0",
@@ -309,7 +314,7 @@
"ts-loader": "^9.5.1",
"ts-node": "^10.9.1",
"ts-node-dev": "^2.0.0",
- "typescript-eslint": "^8.3.0",
+ "typescript-eslint": "^8.6.0",
"webpack-dev-server": "^5.0.4"
},
"engines": {
@@ -417,6 +422,26 @@
"node": ">=6.0.0"
}
},
+ "node_modules/@antfu/install-pkg": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-0.4.1.tgz",
+ "integrity": "sha512-T7yB5QNG29afhWVkVq7XeIMBa5U/vs9mX69YqayXypPRmYzUmzwnYltplHmPtZ4HPCn+sQKeXW8I47wCbuBOjw==",
+ "dependencies": {
+ "package-manager-detector": "^0.2.0",
+ "tinyexec": "^0.3.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/@antfu/utils": {
+ "version": "0.7.10",
+ "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz",
+ "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
"node_modules/@azure/abort-controller": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz",
@@ -429,9 +454,9 @@
}
},
"node_modules/@azure/core-auth": {
- "version": "1.7.2",
- "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz",
- "integrity": "sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==",
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.8.0.tgz",
+ "integrity": "sha512-YvFMowkXzLbXNM11yZtVLhUCmuG0ex7JKOH366ipjmHBhL3vpDcPAeWF+jf0X+jVXwFqo3UhsWUq4kH0ZPdu/g==",
"dependencies": {
"@azure/abort-controller": "^2.0.0",
"@azure/core-util": "^1.1.0",
@@ -541,12 +566,12 @@
}
},
"node_modules/@azure/core-rest-pipeline": {
- "version": "1.16.3",
- "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.3.tgz",
- "integrity": "sha512-VxLk4AHLyqcHsfKe4MZ6IQ+D+ShuByy+RfStKfSjxJoL3WBWq17VNmrz8aT8etKzqc2nAeIyLxScjpzsS4fz8w==",
+ "version": "1.17.0",
+ "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.17.0.tgz",
+ "integrity": "sha512-62Vv8nC+uPId3j86XJ0WI+sBf0jlqTqPUFCBNrGtlaUeQUIXWV/D8GE5A1d+Qx8H7OQojn2WguC8kChD6v0shA==",
"dependencies": {
"@azure/abort-controller": "^2.0.0",
- "@azure/core-auth": "^1.4.0",
+ "@azure/core-auth": "^1.8.0",
"@azure/core-tracing": "^1.0.1",
"@azure/core-util": "^1.9.0",
"@azure/logger": "^1.0.0",
@@ -581,9 +606,9 @@
}
},
"node_modules/@azure/core-util": {
- "version": "1.9.2",
- "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.9.2.tgz",
- "integrity": "sha512-l1Qrqhi4x1aekkV+OlcqsJa4AnAkj5p0JV8omgwjaV9OAbP41lvrMvs+CptfetKkeEaGRGSzby7sjPZEX7+kkQ==",
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.10.0.tgz",
+ "integrity": "sha512-dqLWQsh9Nro1YQU+405POVtXnwrIVqPyfUzc4zXCbThTg7+vNNaiMkwbX9AMXKyoFYFClxmB3s25ZFr3+jZkww==",
"dependencies": {
"@azure/abort-controller": "^2.0.0",
"tslib": "^2.6.2"
@@ -700,11 +725,11 @@
}
},
"node_modules/@babel/generator": {
- "version": "7.25.5",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.5.tgz",
- "integrity": "sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==",
+ "version": "7.25.6",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz",
+ "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==",
"dependencies": {
- "@babel/types": "^7.25.4",
+ "@babel/types": "^7.25.6",
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^2.5.1"
@@ -956,13 +981,13 @@
}
},
"node_modules/@babel/helpers": {
- "version": "7.25.0",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz",
- "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==",
+ "version": "7.25.6",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz",
+ "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==",
"peer": true,
"dependencies": {
"@babel/template": "^7.25.0",
- "@babel/types": "^7.25.0"
+ "@babel/types": "^7.25.6"
},
"engines": {
"node": ">=6.9.0"
@@ -983,11 +1008,11 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.25.4",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.4.tgz",
- "integrity": "sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==",
+ "version": "7.25.6",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz",
+ "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==",
"dependencies": {
- "@babel/types": "^7.25.4"
+ "@babel/types": "^7.25.6"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -1140,11 +1165,11 @@
}
},
"node_modules/@babel/plugin-syntax-import-assertions": {
- "version": "7.24.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz",
- "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==",
+ "version": "7.25.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.6.tgz",
+ "integrity": "sha512-aABl0jHw9bZ2karQ/uUD6XP4u0SG22SJrOHFoL6XB1R7dTovOP4TzTlsxOYC5yQ1pdscVK2JTUnF6QL3ARoAiQ==",
"dependencies": {
- "@babel/helper-plugin-utils": "^7.24.7"
+ "@babel/helper-plugin-utils": "^7.24.8"
},
"engines": {
"node": ">=6.9.0"
@@ -1154,11 +1179,11 @@
}
},
"node_modules/@babel/plugin-syntax-import-attributes": {
- "version": "7.24.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz",
- "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==",
+ "version": "7.25.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz",
+ "integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==",
"dependencies": {
- "@babel/helper-plugin-utils": "^7.24.7"
+ "@babel/helper-plugin-utils": "^7.24.8"
},
"engines": {
"node": ">=6.9.0"
@@ -2251,9 +2276,9 @@
"integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA=="
},
"node_modules/@babel/runtime": {
- "version": "7.25.4",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.4.tgz",
- "integrity": "sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w==",
+ "version": "7.25.6",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz",
+ "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@@ -2262,9 +2287,9 @@
}
},
"node_modules/@babel/runtime-corejs3": {
- "version": "7.25.0",
- "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.25.0.tgz",
- "integrity": "sha512-BOehWE7MgQ8W8Qn0CQnMtg2tHPHPulcS/5AVpFvs2KCK1ET+0WqZqPvnpRpFN81gYoFopdIEJX9Sgjw3ZBccPg==",
+ "version": "7.25.6",
+ "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.25.6.tgz",
+ "integrity": "sha512-Gz0Nrobx8szge6kQQ5Z5MX9L3ObqNwCQY1PSwSNzreFL7aHGxv8Fp2j3ETV6/wWdbiV+mW6OSm8oQhg3Tcsniw==",
"dependencies": {
"core-js-pure": "^3.30.2",
"regenerator-runtime": "^0.14.0"
@@ -2287,15 +2312,15 @@
}
},
"node_modules/@babel/traverse": {
- "version": "7.25.4",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.4.tgz",
- "integrity": "sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==",
+ "version": "7.25.6",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz",
+ "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==",
"dependencies": {
"@babel/code-frame": "^7.24.7",
- "@babel/generator": "^7.25.4",
- "@babel/parser": "^7.25.4",
+ "@babel/generator": "^7.25.6",
+ "@babel/parser": "^7.25.6",
"@babel/template": "^7.25.0",
- "@babel/types": "^7.25.4",
+ "@babel/types": "^7.25.6",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
@@ -2312,9 +2337,9 @@
}
},
"node_modules/@babel/types": {
- "version": "7.25.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.4.tgz",
- "integrity": "sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==",
+ "version": "7.25.6",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz",
+ "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==",
"dependencies": {
"@babel/helper-string-parser": "^7.24.8",
"@babel/helper-validator-identifier": "^7.24.7",
@@ -2568,9 +2593,9 @@
}
},
"node_modules/@eslint-community/regexpp": {
- "version": "4.11.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz",
- "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==",
+ "version": "4.11.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz",
+ "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==",
"engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
}
@@ -2678,9 +2703,9 @@
}
},
"node_modules/@eslint/js": {
- "version": "9.9.1",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz",
- "integrity": "sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==",
+ "version": "9.10.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.10.0.tgz",
+ "integrity": "sha512-fuXtbiP5GWIn8Fz+LWoOMVf/Jxm+aajZYkhi6CuEm4SxymFM+eUWzbO9qXT+L0iCkL5+KGYMCSGxo686H19S1g==",
"license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2694,6 +2719,18 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/@eslint/plugin-kit": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.1.0.tgz",
+ "integrity": "sha512-autAXT203ixhqei9xt+qkYOvY8l6LAFIdT2UXc/RPNeUVfqRF1BV94GTJyVPFKT8nFM6MyVJhjLj9E8JWvf5zQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "levn": "^0.4.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
"node_modules/@ffmpeg/core": {
"version": "0.12.6",
"resolved": "https://registry.npmjs.org/@ffmpeg/core/-/core-0.12.6.tgz",
@@ -2722,29 +2759,29 @@
}
},
"node_modules/@floating-ui/core": {
- "version": "1.6.7",
- "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz",
- "integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==",
+ "version": "1.6.8",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz",
+ "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==",
"dependencies": {
- "@floating-ui/utils": "^0.2.7"
+ "@floating-ui/utils": "^0.2.8"
}
},
"node_modules/@floating-ui/dom": {
- "version": "1.6.10",
- "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz",
- "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==",
+ "version": "1.6.11",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.11.tgz",
+ "integrity": "sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==",
"dependencies": {
"@floating-ui/core": "^1.6.0",
- "@floating-ui/utils": "^0.2.7"
+ "@floating-ui/utils": "^0.2.8"
}
},
"node_modules/@floating-ui/react": {
- "version": "0.26.23",
- "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.23.tgz",
- "integrity": "sha512-9u3i62fV0CFF3nIegiWiRDwOs7OW/KhSUJDNx2MkQM3LbE5zQOY01sL3nelcVBXvX7Ovvo3A49I8ql+20Wg/Hw==",
+ "version": "0.26.24",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.24.tgz",
+ "integrity": "sha512-2ly0pCkZIGEQUq5H8bBK0XJmc1xIK/RM3tvVzY3GBER7IOD1UgmC2Y2tjj4AuS+TC+vTE1KJv2053290jua0Sw==",
"dependencies": {
- "@floating-ui/react-dom": "^2.1.1",
- "@floating-ui/utils": "^0.2.7",
+ "@floating-ui/react-dom": "^2.1.2",
+ "@floating-ui/utils": "^0.2.8",
"tabbable": "^6.0.0"
},
"peerDependencies": {
@@ -2753,9 +2790,9 @@
}
},
"node_modules/@floating-ui/react-dom": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz",
- "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==",
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz",
+ "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==",
"dependencies": {
"@floating-ui/dom": "^1.0.0"
},
@@ -2765,9 +2802,9 @@
}
},
"node_modules/@floating-ui/utils": {
- "version": "0.2.7",
- "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz",
- "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA=="
+ "version": "0.2.8",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz",
+ "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig=="
},
"node_modules/@formatjs/ecma402-abstract": {
"version": "2.0.0",
@@ -2893,6 +2930,22 @@
"@fullcalendar/core": "~6.1.15"
}
},
+ "node_modules/@fullcalendar/interaction": {
+ "version": "6.1.15",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/interaction/-/interaction-6.1.15.tgz",
+ "integrity": "sha512-DOTSkofizM7QItjgu7W68TvKKvN9PSEEvDJceyMbQDvlXHa7pm/WAVtAc6xSDZ9xmB1QramYoWGLHkCYbTW1rQ==",
+ "peerDependencies": {
+ "@fullcalendar/core": "~6.1.15"
+ }
+ },
+ "node_modules/@fullcalendar/list": {
+ "version": "6.1.15",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/list/-/list-6.1.15.tgz",
+ "integrity": "sha512-U1bce04tYDwkFnuVImJSy2XalYIIQr6YusOWRPM/5ivHcJh67Gm8CIMSWpi3KdRSNKFkqBxLPkfZGBMaOcJYug==",
+ "peerDependencies": {
+ "@fullcalendar/core": "~6.1.15"
+ }
+ },
"node_modules/@fullcalendar/multimonth": {
"version": "6.1.15",
"resolved": "https://registry.npmjs.org/@fullcalendar/multimonth/-/multimonth-6.1.15.tgz",
@@ -2904,6 +2957,17 @@
"@fullcalendar/core": "~6.1.15"
}
},
+ "node_modules/@fullcalendar/timegrid": {
+ "version": "6.1.15",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/timegrid/-/timegrid-6.1.15.tgz",
+ "integrity": "sha512-61ORr3A148RtxQ2FNG7JKvacyA/TEVZ7z6I+3E9Oeu3dqTf6M928bFcpehRTIK6zIA6Yifs7BeWHgOE9dFnpbw==",
+ "dependencies": {
+ "@fullcalendar/daygrid": "~6.1.15"
+ },
+ "peerDependencies": {
+ "@fullcalendar/core": "~6.1.15"
+ }
+ },
"node_modules/@googlemaps/js-api-loader": {
"version": "1.16.2",
"resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.16.2.tgz",
@@ -2945,6 +3009,25 @@
"url": "https://github.com/sponsors/nzakas"
}
},
+ "node_modules/@iconify/types": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
+ "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="
+ },
+ "node_modules/@iconify/utils": {
+ "version": "2.1.33",
+ "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.1.33.tgz",
+ "integrity": "sha512-jP9h6v/g0BIZx0p7XGJJVtkVnydtbgTgt9mVNcGDYwaa7UhdHdI9dvoq+gKj9sijMSJKxUPEG2JyjsgXjxL7Kw==",
+ "dependencies": {
+ "@antfu/install-pkg": "^0.4.0",
+ "@antfu/utils": "^0.7.10",
+ "@iconify/types": "^2.0.0",
+ "debug": "^4.3.6",
+ "kolorist": "^1.8.0",
+ "local-pkg": "^0.5.0",
+ "mlly": "^1.7.1"
+ }
+ },
"node_modules/@icons/material": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz",
@@ -3003,9 +3086,9 @@
}
},
"node_modules/@isaacs/cliui/node_modules/ansi-regex": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
- "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+ "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
"engines": {
"node": ">=12"
},
@@ -3118,399 +3201,390 @@
"node": ">=8"
}
},
- "node_modules/@jimp/bmp": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.22.12.tgz",
- "integrity": "sha512-aeI64HD0npropd+AR76MCcvvRaa+Qck6loCOS03CkkxGHN5/r336qTM5HPUdHKMDOGzqknuVPA8+kK1t03z12g==",
+ "node_modules/@jimp/core": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/core/-/core-1.6.0.tgz",
+ "integrity": "sha512-EQQlKU3s9QfdJqiSrZWNTxBs3rKXgO2W+GxNXDtwchF3a4IqxDheFX1ti+Env9hdJXDiYLp2jTRjlxhPthsk8w==",
"dependencies": {
- "@jimp/utils": "^0.22.12",
- "bmp-js": "^0.1.0"
+ "@jimp/file-ops": "1.6.0",
+ "@jimp/types": "1.6.0",
+ "@jimp/utils": "1.6.0",
+ "await-to-js": "^3.0.0",
+ "exif-parser": "^0.1.12",
+ "file-type": "^16.0.0",
+ "mime": "3"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
- "node_modules/@jimp/core": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.22.12.tgz",
- "integrity": "sha512-l0RR0dOPyzMKfjUW1uebzueFEDtCOj9fN6pyTYWWOM/VS4BciXQ1VVrJs8pO3kycGYZxncRKhCoygbNr8eEZQA==",
+ "node_modules/@jimp/diff": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/diff/-/diff-1.6.0.tgz",
+ "integrity": "sha512-+yUAQ5gvRC5D1WHYxjBHZI7JBRusGGSLf8AmPRPCenTzh4PA+wZ1xv2+cYqQwTfQHU5tXYOhA0xDytfHUf1Zyw==",
"dependencies": {
- "@jimp/utils": "^0.22.12",
- "any-base": "^1.1.0",
- "buffer": "^5.2.0",
- "exif-parser": "^0.1.12",
- "file-type": "^16.5.4",
- "isomorphic-fetch": "^3.0.0",
- "pixelmatch": "^4.0.2",
- "tinycolor2": "^1.6.0"
+ "@jimp/plugin-resize": "1.6.0",
+ "@jimp/types": "1.6.0",
+ "@jimp/utils": "1.6.0",
+ "pixelmatch": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@jimp/file-ops": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/file-ops/-/file-ops-1.6.0.tgz",
+ "integrity": "sha512-Dx/bVDmgnRe1AlniRpCKrGRm5YvGmUwbDzt+MAkgmLGf+jvBT75hmMEZ003n9HQI/aPnm/YKnXjg/hOpzNCpHQ==",
+ "engines": {
+ "node": ">=18"
}
},
- "node_modules/@jimp/custom": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.22.12.tgz",
- "integrity": "sha512-xcmww1O/JFP2MrlGUMd3Q78S3Qu6W3mYTXYuIqFq33EorgYHV/HqymHfXy9GjiCJ7OI+7lWx6nYFOzU7M4rd1Q==",
+ "node_modules/@jimp/js-bmp": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/js-bmp/-/js-bmp-1.6.0.tgz",
+ "integrity": "sha512-FU6Q5PC/e3yzLyBDXupR3SnL3htU7S3KEs4e6rjDP6gNEOXRFsWs6YD3hXuXd50jd8ummy+q2WSwuGkr8wi+Gw==",
"dependencies": {
- "@jimp/core": "^0.22.12"
+ "@jimp/core": "1.6.0",
+ "@jimp/types": "1.6.0",
+ "@jimp/utils": "1.6.0",
+ "bmp-ts": "^1.0.9"
+ },
+ "engines": {
+ "node": ">=18"
}
},
- "node_modules/@jimp/gif": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.22.12.tgz",
- "integrity": "sha512-y6BFTJgch9mbor2H234VSjd9iwAhaNf/t3US5qpYIs0TSbAvM02Fbc28IaDETj9+4YB4676sz4RcN/zwhfu1pg==",
+ "node_modules/@jimp/js-gif": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/js-gif/-/js-gif-1.6.0.tgz",
+ "integrity": "sha512-N9CZPHOrJTsAUoWkWZstLPpwT5AwJ0wge+47+ix3++SdSL/H2QzyMqxbcDYNFe4MoI5MIhATfb0/dl/wmX221g==",
"dependencies": {
- "@jimp/utils": "^0.22.12",
+ "@jimp/core": "1.6.0",
+ "@jimp/types": "1.6.0",
"gifwrap": "^0.10.1",
- "omggif": "^1.0.9"
+ "omggif": "^1.0.10"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
- "node_modules/@jimp/jpeg": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.22.12.tgz",
- "integrity": "sha512-Rq26XC/uQWaQKyb/5lksCTCxXhtY01NJeBN+dQv5yNYedN0i7iYu+fXEoRsfaJ8xZzjoANH8sns7rVP4GE7d/Q==",
+ "node_modules/@jimp/js-jpeg": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/js-jpeg/-/js-jpeg-1.6.0.tgz",
+ "integrity": "sha512-6vgFDqeusblf5Pok6B2DUiMXplH8RhIKAryj1yn+007SIAQ0khM1Uptxmpku/0MfbClx2r7pnJv9gWpAEJdMVA==",
"dependencies": {
- "@jimp/utils": "^0.22.12",
+ "@jimp/core": "1.6.0",
+ "@jimp/types": "1.6.0",
"jpeg-js": "^0.4.4"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@jimp/js-png": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/js-png/-/js-png-1.6.0.tgz",
+ "integrity": "sha512-AbQHScy3hDDgMRNfG0tPjL88AV6qKAILGReIa3ATpW5QFjBKpisvUaOqhzJ7Reic1oawx3Riyv152gaPfqsBVg==",
+ "dependencies": {
+ "@jimp/core": "1.6.0",
+ "@jimp/types": "1.6.0",
+ "pngjs": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@jimp/js-tiff": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/js-tiff/-/js-tiff-1.6.0.tgz",
+ "integrity": "sha512-zhReR8/7KO+adijj3h0ZQUOiun3mXUv79zYEAKvE0O+rP7EhgtKvWJOZfRzdZSNv0Pu1rKtgM72qgtwe2tFvyw==",
+ "dependencies": {
+ "@jimp/core": "1.6.0",
+ "@jimp/types": "1.6.0",
+ "utif2": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/plugin-blit": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.22.12.tgz",
- "integrity": "sha512-xslz2ZoFZOPLY8EZ4dC29m168BtDx95D6K80TzgUi8gqT7LY6CsajWO0FAxDwHz6h0eomHMfyGX0stspBrTKnQ==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-1.6.0.tgz",
+ "integrity": "sha512-M+uRWl1csi7qilnSK8uxK4RJMSuVeBiO1AY0+7APnfUbQNZm6hCe0CCFv1Iyw1D/Dhb8ph8fQgm5mwM0eSxgVA==",
"dependencies": {
- "@jimp/utils": "^0.22.12"
+ "@jimp/types": "1.6.0",
+ "@jimp/utils": "1.6.0",
+ "zod": "^3.23.8"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/plugin-blur": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.22.12.tgz",
- "integrity": "sha512-S0vJADTuh1Q9F+cXAwFPlrKWzDj2F9t/9JAbUvaaDuivpyWuImEKXVz5PUZw2NbpuSHjwssbTpOZ8F13iJX4uw==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-1.6.0.tgz",
+ "integrity": "sha512-zrM7iic1OTwUCb0g/rN5y+UnmdEsT3IfuCXCJJNs8SZzP0MkZ1eTvuwK9ZidCuMo4+J3xkzCidRwYXB5CyGZTw==",
"dependencies": {
- "@jimp/utils": "^0.22.12"
+ "@jimp/core": "1.6.0",
+ "@jimp/utils": "1.6.0"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/plugin-circle": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-0.22.12.tgz",
- "integrity": "sha512-SWVXx1yiuj5jZtMijqUfvVOJBwOifFn0918ou4ftoHgegc5aHWW5dZbYPjvC9fLpvz7oSlptNl2Sxr1zwofjTg==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-1.6.0.tgz",
+ "integrity": "sha512-xt1Gp+LtdMKAXfDp3HNaG30SPZW6AQ7dtAtTnoRKorRi+5yCJjKqXRgkewS5bvj8DEh87Ko1ydJfzqS3P2tdWw==",
"dependencies": {
- "@jimp/utils": "^0.22.12"
+ "@jimp/types": "1.6.0",
+ "zod": "^3.23.8"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/plugin-color": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.22.12.tgz",
- "integrity": "sha512-xImhTE5BpS8xa+mAN6j4sMRWaUgUDLoaGHhJhpC+r7SKKErYDR0WQV4yCE4gP+N0gozD0F3Ka1LUSaMXrn7ZIA==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-1.6.0.tgz",
+ "integrity": "sha512-J5q8IVCpkBsxIXM+45XOXTrsyfblyMZg3a9eAo0P7VPH4+CrvyNQwaYatbAIamSIN1YzxmO3DkIZXzRjFSz1SA==",
"dependencies": {
- "@jimp/utils": "^0.22.12",
- "tinycolor2": "^1.6.0"
+ "@jimp/core": "1.6.0",
+ "@jimp/types": "1.6.0",
+ "@jimp/utils": "1.6.0",
+ "tinycolor2": "^1.6.0",
+ "zod": "^3.23.8"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/plugin-contain": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.22.12.tgz",
- "integrity": "sha512-Eo3DmfixJw3N79lWk8q/0SDYbqmKt1xSTJ69yy8XLYQj9svoBbyRpSnHR+n9hOw5pKXytHwUW6nU4u1wegHNoQ==",
- "dependencies": {
- "@jimp/utils": "^0.22.12"
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-1.6.0.tgz",
+ "integrity": "sha512-oN/n+Vdq/Qg9bB4yOBOxtY9IPAtEfES8J1n9Ddx+XhGBYT1/QTU/JYkGaAkIGoPnyYvmLEDqMz2SGihqlpqfzQ==",
+ "dependencies": {
+ "@jimp/core": "1.6.0",
+ "@jimp/plugin-blit": "1.6.0",
+ "@jimp/plugin-resize": "1.6.0",
+ "@jimp/types": "1.6.0",
+ "@jimp/utils": "1.6.0",
+ "zod": "^3.23.8"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5",
- "@jimp/plugin-blit": ">=0.3.5",
- "@jimp/plugin-resize": ">=0.3.5",
- "@jimp/plugin-scale": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/plugin-cover": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.22.12.tgz",
- "integrity": "sha512-z0w/1xH/v/knZkpTNx+E8a7fnasQ2wHG5ze6y5oL2dhH1UufNua8gLQXlv8/W56+4nJ1brhSd233HBJCo01BXA==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-1.6.0.tgz",
+ "integrity": "sha512-Iow0h6yqSC269YUJ8HC3Q/MpCi2V55sMlbkkTTx4zPvd8mWZlC0ykrNDeAy9IJegrQ7v5E99rJwmQu25lygKLA==",
"dependencies": {
- "@jimp/utils": "^0.22.12"
+ "@jimp/core": "1.6.0",
+ "@jimp/plugin-crop": "1.6.0",
+ "@jimp/plugin-resize": "1.6.0",
+ "@jimp/types": "1.6.0",
+ "zod": "^3.23.8"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5",
- "@jimp/plugin-crop": ">=0.3.5",
- "@jimp/plugin-resize": ">=0.3.5",
- "@jimp/plugin-scale": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/plugin-crop": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.22.12.tgz",
- "integrity": "sha512-FNuUN0OVzRCozx8XSgP9MyLGMxNHHJMFt+LJuFjn1mu3k0VQxrzqbN06yIl46TVejhyAhcq5gLzqmSCHvlcBVw==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-1.6.0.tgz",
+ "integrity": "sha512-KqZkEhvs+21USdySCUDI+GFa393eDIzbi1smBqkUPTE+pRwSWMAf01D5OC3ZWB+xZsNla93BDS9iCkLHA8wang==",
"dependencies": {
- "@jimp/utils": "^0.22.12"
+ "@jimp/core": "1.6.0",
+ "@jimp/types": "1.6.0",
+ "@jimp/utils": "1.6.0",
+ "zod": "^3.23.8"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/plugin-displace": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.22.12.tgz",
- "integrity": "sha512-qpRM8JRicxfK6aPPqKZA6+GzBwUIitiHaZw0QrJ64Ygd3+AsTc7BXr+37k2x7QcyCvmKXY4haUrSIsBug4S3CA==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-1.6.0.tgz",
+ "integrity": "sha512-4Y10X9qwr5F+Bo5ME356XSACEF55485j5nGdiyJ9hYzjQP9nGgxNJaZ4SAOqpd+k5sFaIeD7SQ0Occ26uIng5Q==",
"dependencies": {
- "@jimp/utils": "^0.22.12"
+ "@jimp/types": "1.6.0",
+ "@jimp/utils": "1.6.0",
+ "zod": "^3.23.8"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/plugin-dither": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.22.12.tgz",
- "integrity": "sha512-jYgGdSdSKl1UUEanX8A85v4+QUm+PE8vHFwlamaKk89s+PXQe7eVE3eNeSZX4inCq63EHL7cX580dMqkoC3ZLw==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-1.6.0.tgz",
+ "integrity": "sha512-600d1RxY0pKwgyU0tgMahLNKsqEcxGdbgXadCiVCoGd6V6glyCvkNrnnwC0n5aJ56Htkj88PToSdF88tNVZEEQ==",
"dependencies": {
- "@jimp/utils": "^0.22.12"
+ "@jimp/types": "1.6.0"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/plugin-fisheye": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-0.22.12.tgz",
- "integrity": "sha512-LGuUTsFg+fOp6KBKrmLkX4LfyCy8IIsROwoUvsUPKzutSqMJnsm3JGDW2eOmWIS/jJpPaeaishjlxvczjgII+Q==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-1.6.0.tgz",
+ "integrity": "sha512-E5QHKWSCBFtpgZarlmN3Q6+rTQxjirFqo44ohoTjzYVrDI6B6beXNnPIThJgPr0Y9GwfzgyarKvQuQuqCnnfbA==",
"dependencies": {
- "@jimp/utils": "^0.22.12"
+ "@jimp/types": "1.6.0",
+ "@jimp/utils": "1.6.0",
+ "zod": "^3.23.8"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/plugin-flip": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.22.12.tgz",
- "integrity": "sha512-m251Rop7GN8W0Yo/rF9LWk6kNclngyjIJs/VXHToGQ6EGveOSTSQaX2Isi9f9lCDLxt+inBIb7nlaLLxnvHX8Q==",
- "dependencies": {
- "@jimp/utils": "^0.22.12"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5",
- "@jimp/plugin-rotate": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-gaussian": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.22.12.tgz",
- "integrity": "sha512-sBfbzoOmJ6FczfG2PquiK84NtVGeScw97JsCC3rpQv1PHVWyW+uqWFF53+n3c8Y0P2HWlUjflEla2h/vWShvhg==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-1.6.0.tgz",
+ "integrity": "sha512-/+rJVDuBIVOgwoyVkBjUFHtP+wmW0r+r5OQ2GpatQofToPVbJw1DdYWXlwviSx7hvixTWLKVgRWQ5Dw862emDg==",
"dependencies": {
- "@jimp/utils": "^0.22.12"
+ "@jimp/types": "1.6.0",
+ "zod": "^3.23.8"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
- "node_modules/@jimp/plugin-invert": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.22.12.tgz",
- "integrity": "sha512-N+6rwxdB+7OCR6PYijaA/iizXXodpxOGvT/smd/lxeXsZ/empHmFFFJ/FaXcYh19Tm04dGDaXcNF/dN5nm6+xQ==",
+ "node_modules/@jimp/plugin-hash": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-hash/-/plugin-hash-1.6.0.tgz",
+ "integrity": "sha512-wWzl0kTpDJgYVbZdajTf+4NBSKvmI3bRI8q6EH9CVeIHps9VWVsUvEyb7rpbcwVLWYuzDtP2R0lTT6WeBNQH9Q==",
"dependencies": {
- "@jimp/utils": "^0.22.12"
+ "@jimp/core": "1.6.0",
+ "@jimp/js-bmp": "1.6.0",
+ "@jimp/js-jpeg": "1.6.0",
+ "@jimp/js-png": "1.6.0",
+ "@jimp/js-tiff": "1.6.0",
+ "@jimp/plugin-color": "1.6.0",
+ "@jimp/plugin-resize": "1.6.0",
+ "@jimp/types": "1.6.0",
+ "@jimp/utils": "1.6.0",
+ "any-base": "^1.1.0"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/plugin-mask": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.22.12.tgz",
- "integrity": "sha512-4AWZg+DomtpUA099jRV8IEZUfn1wLv6+nem4NRJC7L/82vxzLCgXKTxvNvBcNmJjT9yS1LAAmiJGdWKXG63/NA==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-1.6.0.tgz",
+ "integrity": "sha512-Cwy7ExSJMZszvkad8NV8o/Z92X2kFUFM8mcDAhNVxU0Q6tA0op2UKRJY51eoK8r6eds/qak3FQkXakvNabdLnA==",
"dependencies": {
- "@jimp/utils": "^0.22.12"
+ "@jimp/types": "1.6.0",
+ "zod": "^3.23.8"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
- "node_modules/@jimp/plugin-normalize": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.22.12.tgz",
- "integrity": "sha512-0So0rexQivnWgnhacX4cfkM2223YdExnJTTy6d06WbkfZk5alHUx8MM3yEzwoCN0ErO7oyqEWRnEkGC+As1FtA==",
- "dependencies": {
- "@jimp/utils": "^0.22.12"
+ "node_modules/@jimp/plugin-print": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-1.6.0.tgz",
+ "integrity": "sha512-zarTIJi8fjoGMSI/M3Xh5yY9T65p03XJmPsuNet19K/Q7mwRU6EV2pfj+28++2PV2NJ+htDF5uecAlnGyxFN2A==",
+ "dependencies": {
+ "@jimp/core": "1.6.0",
+ "@jimp/js-jpeg": "1.6.0",
+ "@jimp/js-png": "1.6.0",
+ "@jimp/plugin-blit": "1.6.0",
+ "@jimp/types": "1.6.0",
+ "parse-bmfont-ascii": "^1.0.6",
+ "parse-bmfont-binary": "^1.0.6",
+ "parse-bmfont-xml": "^1.1.6",
+ "simple-xml-to-json": "^1.2.2",
+ "zod": "^3.23.8"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
- "node_modules/@jimp/plugin-print": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.22.12.tgz",
- "integrity": "sha512-c7TnhHlxm87DJeSnwr/XOLjJU/whoiKYY7r21SbuJ5nuH+7a78EW1teOaj5gEr2wYEd7QtkFqGlmyGXY/YclyQ==",
+ "node_modules/@jimp/plugin-quantize": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-quantize/-/plugin-quantize-1.6.0.tgz",
+ "integrity": "sha512-EmzZ/s9StYQwbpG6rUGBCisc3f64JIhSH+ncTJd+iFGtGo0YvSeMdAd+zqgiHpfZoOL54dNavZNjF4otK+mvlg==",
"dependencies": {
- "@jimp/utils": "^0.22.12",
- "load-bmfont": "^1.4.1"
+ "image-q": "^4.0.0",
+ "zod": "^3.23.8"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5",
- "@jimp/plugin-blit": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/plugin-resize": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.22.12.tgz",
- "integrity": "sha512-3NyTPlPbTnGKDIbaBgQ3HbE6wXbAlFfxHVERmrbqAi8R3r6fQPxpCauA8UVDnieg5eo04D0T8nnnNIX//i/sXg==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-1.6.0.tgz",
+ "integrity": "sha512-uSUD1mqXN9i1SGSz5ov3keRZ7S9L32/mAQG08wUwZiEi5FpbV0K8A8l1zkazAIZi9IJzLlTauRNU41Mi8IF9fA==",
"dependencies": {
- "@jimp/utils": "^0.22.12"
+ "@jimp/core": "1.6.0",
+ "@jimp/types": "1.6.0",
+ "zod": "^3.23.8"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/plugin-rotate": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.22.12.tgz",
- "integrity": "sha512-9YNEt7BPAFfTls2FGfKBVgwwLUuKqy+E8bDGGEsOqHtbuhbshVGxN2WMZaD4gh5IDWvR+emmmPPWGgaYNYt1gA==",
- "dependencies": {
- "@jimp/utils": "^0.22.12"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5",
- "@jimp/plugin-blit": ">=0.3.5",
- "@jimp/plugin-crop": ">=0.3.5",
- "@jimp/plugin-resize": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-scale": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.22.12.tgz",
- "integrity": "sha512-dghs92qM6MhHj0HrV2qAwKPMklQtjNpoYgAB94ysYpsXslhRTiPisueSIELRwZGEr0J0VUxpUY7HgJwlSIgGZw==",
- "dependencies": {
- "@jimp/utils": "^0.22.12"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5",
- "@jimp/plugin-resize": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-shadow": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.22.12.tgz",
- "integrity": "sha512-FX8mTJuCt7/3zXVoeD/qHlm4YH2bVqBuWQHXSuBK054e7wFRnRnbSLPUqAwSeYP3lWqpuQzJtgiiBxV3+WWwTg==",
- "dependencies": {
- "@jimp/utils": "^0.22.12"
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-1.6.0.tgz",
+ "integrity": "sha512-JagdjBLnUZGSG4xjCLkIpQOZZ3Mjbg8aGCCi4G69qR+OjNpOeGI7N2EQlfK/WE8BEHOW5vdjSyglNqcYbQBWRw==",
+ "dependencies": {
+ "@jimp/core": "1.6.0",
+ "@jimp/plugin-crop": "1.6.0",
+ "@jimp/plugin-resize": "1.6.0",
+ "@jimp/types": "1.6.0",
+ "@jimp/utils": "1.6.0",
+ "zod": "^3.23.8"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5",
- "@jimp/plugin-blur": ">=0.3.5",
- "@jimp/plugin-resize": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/plugin-threshold": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.22.12.tgz",
- "integrity": "sha512-4x5GrQr1a/9L0paBC/MZZJjjgjxLYrqSmWd+e+QfAEPvmRxdRoQ5uKEuNgXnm9/weHQBTnQBQsOY2iFja+XGAw==",
- "dependencies": {
- "@jimp/utils": "^0.22.12"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5",
- "@jimp/plugin-color": ">=0.8.0",
- "@jimp/plugin-resize": ">=0.8.0"
- }
- },
- "node_modules/@jimp/plugins": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.22.12.tgz",
- "integrity": "sha512-yBJ8vQrDkBbTgQZLty9k4+KtUQdRjsIDJSPjuI21YdVeqZxYywifHl4/XWILoTZsjTUASQcGoH0TuC0N7xm3ww==",
- "dependencies": {
- "@jimp/plugin-blit": "^0.22.12",
- "@jimp/plugin-blur": "^0.22.12",
- "@jimp/plugin-circle": "^0.22.12",
- "@jimp/plugin-color": "^0.22.12",
- "@jimp/plugin-contain": "^0.22.12",
- "@jimp/plugin-cover": "^0.22.12",
- "@jimp/plugin-crop": "^0.22.12",
- "@jimp/plugin-displace": "^0.22.12",
- "@jimp/plugin-dither": "^0.22.12",
- "@jimp/plugin-fisheye": "^0.22.12",
- "@jimp/plugin-flip": "^0.22.12",
- "@jimp/plugin-gaussian": "^0.22.12",
- "@jimp/plugin-invert": "^0.22.12",
- "@jimp/plugin-mask": "^0.22.12",
- "@jimp/plugin-normalize": "^0.22.12",
- "@jimp/plugin-print": "^0.22.12",
- "@jimp/plugin-resize": "^0.22.12",
- "@jimp/plugin-rotate": "^0.22.12",
- "@jimp/plugin-scale": "^0.22.12",
- "@jimp/plugin-shadow": "^0.22.12",
- "@jimp/plugin-threshold": "^0.22.12",
- "timm": "^1.6.1"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/png": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.22.12.tgz",
- "integrity": "sha512-Mrp6dr3UTn+aLK8ty/dSKELz+Otdz1v4aAXzV5q53UDD2rbB5joKVJ/ChY310B+eRzNxIovbUF1KVrUsYdE8Hg==",
- "dependencies": {
- "@jimp/utils": "^0.22.12",
- "pngjs": "^6.0.0"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/tiff": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.22.12.tgz",
- "integrity": "sha512-E1LtMh4RyJsoCAfAkBRVSYyZDTtLq9p9LUiiYP0vPtXyxX4BiYBUYihTLSBlCQg5nF2e4OpQg7SPrLdJ66u7jg==",
- "dependencies": {
- "utif2": "^4.0.1"
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-1.6.0.tgz",
+ "integrity": "sha512-M59m5dzLoHOVWdM41O8z9SyySzcDn43xHseOH0HavjsfQsT56GGCC4QzU1banJidbUrePhzoEdS42uFE8Fei8w==",
+ "dependencies": {
+ "@jimp/core": "1.6.0",
+ "@jimp/plugin-color": "1.6.0",
+ "@jimp/plugin-hash": "1.6.0",
+ "@jimp/types": "1.6.0",
+ "@jimp/utils": "1.6.0",
+ "zod": "^3.23.8"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/types": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.22.12.tgz",
- "integrity": "sha512-wwKYzRdElE1MBXFREvCto5s699izFHNVvALUv79GXNbsOVqlwlOxlWJ8DuyOGIXoLP4JW/m30YyuTtfUJgMRMA==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/types/-/types-1.6.0.tgz",
+ "integrity": "sha512-7UfRsiKo5GZTAATxm2qQ7jqmUXP0DxTArztllTcYdyw6Xi5oT4RaoXynVtCD4UyLK5gJgkZJcwonoijrhYFKfg==",
"dependencies": {
- "@jimp/bmp": "^0.22.12",
- "@jimp/gif": "^0.22.12",
- "@jimp/jpeg": "^0.22.12",
- "@jimp/png": "^0.22.12",
- "@jimp/tiff": "^0.22.12",
- "timm": "^1.6.1"
+ "zod": "^3.23.8"
},
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jimp/utils": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.22.12.tgz",
- "integrity": "sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-1.6.0.tgz",
+ "integrity": "sha512-gqFTGEosKbOkYF/WFj26jMHOI5OH2jeP1MmC/zbK6BF6VJBf8rIC5898dPfSzZEbSA0wbbV5slbntWVc5PKLFA==",
"dependencies": {
- "regenerator-runtime": "^0.13.3"
+ "@jimp/types": "1.6.0",
+ "tinycolor2": "^1.6.0"
+ },
+ "engines": {
+ "node": ">=18"
}
},
- "node_modules/@jimp/utils/node_modules/regenerator-runtime": {
- "version": "0.13.11",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
- "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
- },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
@@ -3796,48 +3870,87 @@
}
},
"node_modules/@mermaid-js/parser": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.2.0.tgz",
- "integrity": "sha512-33dyFdhwsX9n4+E8SRj1ulxwAgwCj9RyCMtoqXD5cDfS9F6y9xmvmjFjHoPaViH4H7I7BXD8yP/XEWig5XrHSQ==",
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.3.0.tgz",
+ "integrity": "sha512-HsvL6zgE5sUPGgkIDlmAWR1HTNHz2Iy11BAWPTa4Jjabkpguy4Ze2gzfLrg6pdRuBvFwgUYyxiaNqZwrEEXepA==",
"dependencies": {
"langium": "3.0.0"
}
},
+ "node_modules/@module-federation/runtime": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.5.1.tgz",
+ "integrity": "sha512-xgiMUWwGLWDrvZc9JibuEbXIbhXg6z2oUkemogSvQ4LKvrl/n0kbqP1Blk669mXzyWbqtSp6PpvNdwaE1aN5xQ==",
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "@module-federation/sdk": "0.5.1"
+ }
+ },
+ "node_modules/@module-federation/runtime-tools": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.5.1.tgz",
+ "integrity": "sha512-nfBedkoZ3/SWyO0hnmaxuz0R0iGPSikHZOAZ0N/dVSQaIzlffUo35B5nlC2wgWIc0JdMZfkwkjZRrnuuDIJbzg==",
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "@module-federation/runtime": "0.5.1",
+ "@module-federation/webpack-bundler-runtime": "0.5.1"
+ }
+ },
+ "node_modules/@module-federation/sdk": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.5.1.tgz",
+ "integrity": "sha512-exvchtjNURJJkpqjQ3/opdbfeT2wPKvrbnGnyRkrwW5o3FH1LaST1tkiNviT6OXTexGaVc2DahbdniQHVtQ7pA==",
+ "optional": true,
+ "peer": true
+ },
+ "node_modules/@module-federation/webpack-bundler-runtime": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.5.1.tgz",
+ "integrity": "sha512-mMhRFH0k2VjwHt3Jol9JkUsmI/4XlrAoBG3E0o7HoyoPYv1UFOWyqAflfANcUPgbYpvqmyLzDcO+3IT36LXnrA==",
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "@module-federation/runtime": "0.5.1",
+ "@module-federation/sdk": "0.5.1"
+ }
+ },
"node_modules/@mongodb-js/saslprep": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz",
- "integrity": "sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==",
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz",
+ "integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==",
"dependencies": {
"sparse-bitfield": "^3.0.3"
}
},
"node_modules/@mui/core-downloads-tracker": {
- "version": "5.16.7",
- "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.7.tgz",
- "integrity": "sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.0.tgz",
+ "integrity": "sha512-covEnIn/2er5YdtuukDRA52kmARhKrHjOvPsyTFMQApZdrTBI4h8jbEy2mxZqwMwcAFS9coonQXnEZKL1rUNdQ==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
}
},
"node_modules/@mui/icons-material": {
- "version": "5.16.7",
- "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.7.tgz",
- "integrity": "sha512-UrGwDJCXEszbDI7yV047BYU5A28eGJ79keTCP4cc74WyncuVrnurlmIRxaHL8YK+LI1Kzq+/JM52IAkNnv4u+Q==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.1.0.tgz",
+ "integrity": "sha512-HxfB0jxwiMTYMN8gAnYn3avbF1aDrqBEuGIj6JDQ3YkLl650E1Wy8AIhwwyP47wdrv0at9aAR0iOO6VLb74A9w==",
"dependencies": {
- "@babel/runtime": "^7.23.9"
+ "@babel/runtime": "^7.25.6"
},
"engines": {
- "node": ">=12.0.0"
+ "node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
- "@mui/material": "^5.0.0",
- "@types/react": "^17.0.0 || ^18.0.0",
- "react": "^17.0.0 || ^18.0.0"
+ "@mui/material": "^6.1.0",
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
@@ -3846,25 +3959,25 @@
}
},
"node_modules/@mui/material": {
- "version": "5.16.7",
- "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.7.tgz",
- "integrity": "sha512-cwwVQxBhK60OIOqZOVLFt55t01zmarKJiJUWbk0+8s/Ix5IaUzAShqlJchxsIQ4mSrWqgcKCCXKtIlG5H+/Jmg==",
- "dependencies": {
- "@babel/runtime": "^7.23.9",
- "@mui/core-downloads-tracker": "^5.16.7",
- "@mui/system": "^5.16.7",
- "@mui/types": "^7.2.15",
- "@mui/utils": "^5.16.6",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.0.tgz",
+ "integrity": "sha512-4MJ46vmy1xbm8x+ZdRcWm8jEMMowdS8pYlhKQzg/qoKhOcLhImZvf2Jn6z9Dj6gl+lY+C/0MxaHF/avAAGys3Q==",
+ "dependencies": {
+ "@babel/runtime": "^7.25.6",
+ "@mui/core-downloads-tracker": "^6.1.0",
+ "@mui/system": "^6.1.0",
+ "@mui/types": "^7.2.16",
+ "@mui/utils": "^6.1.0",
"@popperjs/core": "^2.11.8",
- "@types/react-transition-group": "^4.4.10",
- "clsx": "^2.1.0",
+ "@types/react-transition-group": "^4.4.11",
+ "clsx": "^2.1.1",
"csstype": "^3.1.3",
"prop-types": "^15.8.1",
"react-is": "^18.3.1",
"react-transition-group": "^4.4.5"
},
"engines": {
- "node": ">=12.0.0"
+ "node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
@@ -3873,9 +3986,10 @@
"peerDependencies": {
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
- "@types/react": "^17.0.0 || ^18.0.0",
- "react": "^17.0.0 || ^18.0.0",
- "react-dom": "^17.0.0 || ^18.0.0"
+ "@mui/material-pigment-css": "^6.1.0",
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
@@ -3884,30 +3998,33 @@
"@emotion/styled": {
"optional": true
},
+ "@mui/material-pigment-css": {
+ "optional": true
+ },
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/private-theming": {
- "version": "5.16.6",
- "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz",
- "integrity": "sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.0.tgz",
+ "integrity": "sha512-+L5qccs4gwsR0r1dgjqhN24QEQRkqIbfOdxILyMbMkuI50x6wNyt9XrV+J3WtjtZTMGJCrUa5VmZBE6OEPGPWA==",
"dependencies": {
- "@babel/runtime": "^7.23.9",
- "@mui/utils": "^5.16.6",
+ "@babel/runtime": "^7.25.6",
+ "@mui/utils": "^6.1.0",
"prop-types": "^15.8.1"
},
"engines": {
- "node": ">=12.0.0"
+ "node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
- "@types/react": "^17.0.0 || ^18.0.0",
- "react": "^17.0.0 || ^18.0.0"
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
@@ -3916,17 +4033,18 @@
}
},
"node_modules/@mui/styled-engine": {
- "version": "5.16.6",
- "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz",
- "integrity": "sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.0.tgz",
+ "integrity": "sha512-MZ+vtaCkjamrT41+b0Er9OMenjAtP/32+L6fARL9/+BZKuV2QbR3q3TmavT2x0NhDu35IM03s4yKqj32Ziqnyg==",
"dependencies": {
- "@babel/runtime": "^7.23.9",
- "@emotion/cache": "^11.11.0",
+ "@babel/runtime": "^7.25.6",
+ "@emotion/cache": "^11.13.1",
+ "@emotion/sheet": "^1.4.0",
"csstype": "^3.1.3",
"prop-types": "^15.8.1"
},
"engines": {
- "node": ">=12.0.0"
+ "node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
@@ -3935,7 +4053,7 @@
"peerDependencies": {
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
- "react": "^17.0.0 || ^18.0.0"
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
@@ -3947,21 +4065,21 @@
}
},
"node_modules/@mui/system": {
- "version": "5.16.7",
- "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.7.tgz",
- "integrity": "sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA==",
- "dependencies": {
- "@babel/runtime": "^7.23.9",
- "@mui/private-theming": "^5.16.6",
- "@mui/styled-engine": "^5.16.6",
- "@mui/types": "^7.2.15",
- "@mui/utils": "^5.16.6",
- "clsx": "^2.1.0",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.0.tgz",
+ "integrity": "sha512-NumkGDqT6EdXfcoFLYQ+M4XlTW5hH3+aK48xAbRqKPXJfxl36CBt4DLduw/Voa5dcayGus9T6jm1AwU2hoJ5hQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.25.6",
+ "@mui/private-theming": "^6.1.0",
+ "@mui/styled-engine": "^6.1.0",
+ "@mui/types": "^7.2.16",
+ "@mui/utils": "^6.1.0",
+ "clsx": "^2.1.1",
"csstype": "^3.1.3",
"prop-types": "^15.8.1"
},
"engines": {
- "node": ">=12.0.0"
+ "node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
@@ -3970,8 +4088,8 @@
"peerDependencies": {
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
- "@types/react": "^17.0.0 || ^18.0.0",
- "react": "^17.0.0 || ^18.0.0"
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
@@ -3999,27 +4117,27 @@
}
},
"node_modules/@mui/utils": {
- "version": "5.16.6",
- "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz",
- "integrity": "sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.0.tgz",
+ "integrity": "sha512-oT8ZzMISRUhTVpdbYzY0CgrCBb3t/YEdcaM13tUnuTjZ15pdA6g5lx15ZJUdgYXV6PbJdw7tDQgMEr4uXK5TXQ==",
"dependencies": {
- "@babel/runtime": "^7.23.9",
- "@mui/types": "^7.2.15",
+ "@babel/runtime": "^7.25.6",
+ "@mui/types": "^7.2.16",
"@types/prop-types": "^15.7.12",
"clsx": "^2.1.1",
"prop-types": "^15.8.1",
"react-is": "^18.3.1"
},
"engines": {
- "node": ">=12.0.0"
+ "node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
- "@types/react": "^17.0.0 || ^18.0.0",
- "react": "^17.0.0 || ^18.0.0"
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
@@ -7114,6 +7232,71 @@
"unicode-trie": "^0.3.0"
}
},
+ "node_modules/@rspack/binding": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.0.0.tgz",
+ "integrity": "sha512-eLyqSEM1h/exJYn98k+9MRktP8AYDB13x5oVn8hoxVucuhk0TubFqQSX8h9SQcZp1O3j/Z8eWWwOaNPe3JU40Q==",
+ "optional": true,
+ "peer": true,
+ "optionalDependencies": {
+ "@rspack/binding-darwin-arm64": "1.0.0",
+ "@rspack/binding-darwin-x64": "1.0.0",
+ "@rspack/binding-linux-arm64-gnu": "1.0.0",
+ "@rspack/binding-linux-arm64-musl": "1.0.0",
+ "@rspack/binding-linux-x64-gnu": "1.0.0",
+ "@rspack/binding-linux-x64-musl": "1.0.0",
+ "@rspack/binding-win32-arm64-msvc": "1.0.0",
+ "@rspack/binding-win32-ia32-msvc": "1.0.0",
+ "@rspack/binding-win32-x64-msvc": "1.0.0"
+ }
+ },
+ "node_modules/@rspack/binding-darwin-x64": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.0.0.tgz",
+ "integrity": "sha512-qhTXm9wUhv2lBjsqqfCu59RchH1/2jursdPAmTqGc7zMReZdZvtJs2Ri6Ma1M48BLLu+7fS4fbL8Rw1g78TOOQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "peer": true
+ },
+ "node_modules/@rspack/core": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.0.0.tgz",
+ "integrity": "sha512-F4RA9uOLLvD1oTKa96Gcly+Sro1qaqPNENadFyiPwepa7DrwexQa/ym6CQKbvKMOYGKlVSFDPUmgFAirz35ETg==",
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "@module-federation/runtime-tools": "0.5.1",
+ "@rspack/binding": "1.0.0",
+ "@rspack/lite-tapable": "1.0.0",
+ "caniuse-lite": "^1.0.30001616"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ },
+ "peerDependencies": {
+ "@swc/helpers": ">=0.5.1"
+ },
+ "peerDependenciesMeta": {
+ "@swc/helpers": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rspack/lite-tapable": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@rspack/lite-tapable/-/lite-tapable-1.0.0.tgz",
+ "integrity": "sha512-7MZf4lburSUZoEenwazwUDKHhqyfnLCGnQ/tKcUtztfmVzfjZfRn/EaiT0AKkYGnL2U8AGsw89oUeVyvaOLVCw==",
+ "optional": true,
+ "peer": true,
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
"node_modules/@sec-ant/readable-stream": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
@@ -7137,9 +7320,9 @@
"integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="
},
"node_modules/@sindresorhus/is": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.0.0.tgz",
- "integrity": "sha512-WDTlVTyvFivSOuyvMeedzg2hdoBLZ3f1uNVuEida2Rl9BrfjrIRjWA/VZIrMRLvSwJYCAlCRA3usDt1THytxWQ==",
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.0.1.tgz",
+ "integrity": "sha512-QWLl2P+rsCJeofkDNIT3WFmb6NrRud1SUYW8dIhXK/46XFV8Q/g7Bsvib0Askb0reRLe+WYPeeE+l5cH7SlkuQ==",
"engines": {
"node": ">=18"
},
@@ -7181,9 +7364,9 @@
}
},
"node_modules/@swc/helpers": {
- "version": "0.5.12",
- "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.12.tgz",
- "integrity": "sha512-KMZNXiGibsW9kvZAO1Pam2JPTDBm+KSHMMHWdsyI/1DbIZjT2A6Gy3hblVXUMEDvUAKq+e0vL0X0o54owWji7g==",
+ "version": "0.5.13",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.13.tgz",
+ "integrity": "sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==",
"dependencies": {
"tslib": "^2.4.0"
}
@@ -9506,9 +9689,9 @@
"dev": true
},
"node_modules/@types/mocha": {
- "version": "10.0.7",
- "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.7.tgz",
- "integrity": "sha512-GN8yJ1mNTcFcah/wKEFIJckJx9iJLoMSzWcfRRuxz/Jk+U6KQNnml+etbtxFK8lPjzOw3zp4Ha/kjSst9fsHYw==",
+ "version": "10.0.8",
+ "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.8.tgz",
+ "integrity": "sha512-HfMcUmy9hTMJh66VNcmeC9iVErIZJli2bszuXc6julh5YGuRb/W5OnkHjwLNYdFlMis0sY3If5SEAp+PktdJjw==",
"dev": true
},
"node_modules/@types/ms": {
@@ -9517,9 +9700,9 @@
"integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g=="
},
"node_modules/@types/node": {
- "version": "22.5.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz",
- "integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==",
+ "version": "22.5.5",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz",
+ "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==",
"dependencies": {
"undici-types": "~6.19.2"
}
@@ -9543,9 +9726,9 @@
}
},
"node_modules/@types/nodemailer": {
- "version": "6.4.15",
- "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.15.tgz",
- "integrity": "sha512-0EBJxawVNjPkng1zm2vopRctuWVCxk34JcIlRuXSf54habUWdz1FB7wHDqOqvDa8Mtpt0Q3LTXQkAs2LNyK5jQ==",
+ "version": "6.4.16",
+ "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.16.tgz",
+ "integrity": "sha512-uz6hN6Pp0upXMcilM61CoKyjT7sskBoOWpptkjjJp8jIMlTdc3xG01U7proKkXzruMS4hS0zqtHNkNPFB20rKQ==",
"dev": true,
"dependencies": {
"@types/node": "*"
@@ -9633,14 +9816,14 @@
"integrity": "sha512-+gbBHbNCVGGYw1S9lAIIvrHW47UYOhMIFUsJcMkMrzy1Jf0vulBN3XQIjPgnoOXveMuHnF3b57fXROnY/Or7eg=="
},
"node_modules/@types/prop-types": {
- "version": "15.7.12",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
- "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q=="
+ "version": "15.7.13",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
+ "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA=="
},
"node_modules/@types/qs": {
- "version": "6.9.15",
- "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz",
- "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==",
+ "version": "6.9.16",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz",
+ "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==",
"dev": true
},
"node_modules/@types/range-parser": {
@@ -9659,9 +9842,9 @@
}
},
"node_modules/@types/react": {
- "version": "18.3.4",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.4.tgz",
- "integrity": "sha512-J7W30FTdfCxDDjmfRM+/JqLHBIyl7xUIp9kwK637FGmY7+mkSFSe6L4jpZzhj5QMfLssSDP4/i75AKkrdC7/Jw==",
+ "version": "18.3.7",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.7.tgz",
+ "integrity": "sha512-KUnDCJF5+AiZd8owLIeVHqmW9yM4sqmDVf2JRJiBMFkGvkoZ4/WyV2lL4zVsoinmRS/W3FeEdZLEWFRofnT2FQ==",
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
@@ -9919,9 +10102,9 @@
"dev": true
},
"node_modules/@types/web": {
- "version": "0.0.157",
- "resolved": "https://registry.npmjs.org/@types/web/-/web-0.0.157.tgz",
- "integrity": "sha512-erqzRlWBxaV7qI0g5rIkHRRxQ3kKmqqhokqgnSy3UEQYIl+5qNCU7DwdPaOke3ZHRXmbrjpGgSc4bjM4ItSDnw=="
+ "version": "0.0.163",
+ "resolved": "https://registry.npmjs.org/@types/web/-/web-0.0.163.tgz",
+ "integrity": "sha512-5Pg2gKfulo186wFnv+YXx0luJGWQ94cCY2/Dy8lU5WAE50FdBoOK45uBbp8FceOSpLJ4UW3dmTW5tvsN9uuX7A=="
},
"node_modules/@types/webgl-ext": {
"version": "0.0.30",
@@ -10005,16 +10188,17 @@
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.3.0.tgz",
- "integrity": "sha512-FLAIn63G5KH+adZosDYiutqkOkYEx0nvcwNNfJAf+c7Ae/H35qWwTYvPZUKFj5AS+WfHG/WJJfWnDnyNUlp8UA==",
+ "version": "8.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.6.0.tgz",
+ "integrity": "sha512-UOaz/wFowmoh2G6Mr9gw60B1mm0MzUtm6Ic8G2yM1Le6gyj5Loi/N+O5mocugRGY+8OeeKmkMmbxNqUCq3B4Sg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.3.0",
- "@typescript-eslint/type-utils": "8.3.0",
- "@typescript-eslint/utils": "8.3.0",
- "@typescript-eslint/visitor-keys": "8.3.0",
+ "@typescript-eslint/scope-manager": "8.6.0",
+ "@typescript-eslint/type-utils": "8.6.0",
+ "@typescript-eslint/utils": "8.6.0",
+ "@typescript-eslint/visitor-keys": "8.6.0",
"graphemer": "^1.4.0",
"ignore": "^5.3.1",
"natural-compare": "^1.4.0",
@@ -10038,15 +10222,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.3.0.tgz",
- "integrity": "sha512-h53RhVyLu6AtpUzVCYLPhZGL5jzTD9fZL+SYf/+hYOx2bDkyQXztXSc4tbvKYHzfMXExMLiL9CWqJmVz6+78IQ==",
+ "version": "8.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.6.0.tgz",
+ "integrity": "sha512-eQcbCuA2Vmw45iGfcyG4y6rS7BhWfz9MQuk409WD47qMM+bKCGQWXxvoOs1DUp+T7UBMTtRTVT+kXr7Sh4O9Ow==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
- "@typescript-eslint/scope-manager": "8.3.0",
- "@typescript-eslint/types": "8.3.0",
- "@typescript-eslint/typescript-estree": "8.3.0",
- "@typescript-eslint/visitor-keys": "8.3.0",
+ "@typescript-eslint/scope-manager": "8.6.0",
+ "@typescript-eslint/types": "8.6.0",
+ "@typescript-eslint/typescript-estree": "8.6.0",
+ "@typescript-eslint/visitor-keys": "8.6.0",
"debug": "^4.3.4"
},
"engines": {
@@ -10066,13 +10251,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.3.0.tgz",
- "integrity": "sha512-mz2X8WcN2nVu5Hodku+IR8GgCOl4C0G/Z1ruaWN4dgec64kDBabuXyPAr+/RgJtumv8EEkqIzf3X2U5DUKB2eg==",
+ "version": "8.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.6.0.tgz",
+ "integrity": "sha512-ZuoutoS5y9UOxKvpc/GkvF4cuEmpokda4wRg64JEia27wX+PysIE9q+lzDtlHHgblwUWwo5/Qn+/WyTUvDwBHw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.3.0",
- "@typescript-eslint/visitor-keys": "8.3.0"
+ "@typescript-eslint/types": "8.6.0",
+ "@typescript-eslint/visitor-keys": "8.6.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -10083,13 +10269,14 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.3.0.tgz",
- "integrity": "sha512-wrV6qh//nLbfXZQoj32EXKmwHf4b7L+xXLrP3FZ0GOUU72gSvLjeWUl5J5Ue5IwRxIV1TfF73j/eaBapxx99Lg==",
+ "version": "8.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.6.0.tgz",
+ "integrity": "sha512-dtePl4gsuenXVwC7dVNlb4mGDcKjDT/Ropsk4za/ouMBPplCLyznIaR+W65mvCvsyS97dymoBRrioEXI7k0XIg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/typescript-estree": "8.3.0",
- "@typescript-eslint/utils": "8.3.0",
+ "@typescript-eslint/typescript-estree": "8.6.0",
+ "@typescript-eslint/utils": "8.6.0",
"debug": "^4.3.4",
"ts-api-utils": "^1.3.0"
},
@@ -10107,10 +10294,11 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.3.0.tgz",
- "integrity": "sha512-y6sSEeK+facMaAyixM36dQ5NVXTnKWunfD1Ft4xraYqxP0lC0POJmIaL/mw72CUMqjY9qfyVfXafMeaUj0noWw==",
+ "version": "8.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.6.0.tgz",
+ "integrity": "sha512-rojqFZGd4MQxw33SrOy09qIDS8WEldM8JWtKQLAjf/X5mGSeEFh5ixQlxssMNyPslVIk9yzWqXCsV2eFhYrYUw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
@@ -10120,13 +10308,14 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.3.0.tgz",
- "integrity": "sha512-Mq7FTHl0R36EmWlCJWojIC1qn/ZWo2YiWYc1XVtasJ7FIgjo0MVv9rZWXEE7IK2CGrtwe1dVOxWwqXUdNgfRCA==",
+ "version": "8.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.6.0.tgz",
+ "integrity": "sha512-MOVAzsKJIPIlLK239l5s06YXjNqpKTVhBVDnqUumQJja5+Y94V3+4VUFRA0G60y2jNnTVwRCkhyGQpavfsbq/g==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
- "@typescript-eslint/types": "8.3.0",
- "@typescript-eslint/visitor-keys": "8.3.0",
+ "@typescript-eslint/types": "8.6.0",
+ "@typescript-eslint/visitor-keys": "8.6.0",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
@@ -10152,6 +10341,7 @@
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
@@ -10167,6 +10357,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"dev": true,
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@@ -10175,15 +10366,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.3.0.tgz",
- "integrity": "sha512-F77WwqxIi/qGkIGOGXNBLV7nykwfjLsdauRB/DOFPdv6LTF3BHHkBpq81/b5iMPSF055oO2BiivDJV4ChvNtXA==",
+ "version": "8.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.6.0.tgz",
+ "integrity": "sha512-eNp9cWnYf36NaOVjkEUznf6fEgVy1TWpE0o52e4wtojjBx7D1UV2WAWGzR+8Y5lVFtpMLPwNbC67T83DWSph4A==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
- "@typescript-eslint/scope-manager": "8.3.0",
- "@typescript-eslint/types": "8.3.0",
- "@typescript-eslint/typescript-estree": "8.3.0"
+ "@typescript-eslint/scope-manager": "8.6.0",
+ "@typescript-eslint/types": "8.6.0",
+ "@typescript-eslint/typescript-estree": "8.6.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -10197,12 +10389,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.3.0.tgz",
- "integrity": "sha512-RmZwrTbQ9QveF15m/Cl28n0LXD6ea2CjkhH5rQ55ewz3H24w+AMCJHPVYaZ8/0HoG8Z3cLLFFycRXxeO2tz9FA==",
+ "version": "8.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.6.0.tgz",
+ "integrity": "sha512-wapVFfZg9H0qOYh4grNVQiMklJGluQrOUiOhYRrQWhx7BY/+I1IYb8BczWNbbUpO+pqy0rDciv3lQH5E1bCLrg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.3.0",
+ "@typescript-eslint/types": "8.6.0",
"eslint-visitor-keys": "^3.4.3"
},
"engines": {
@@ -10218,6 +10411,7 @@
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
@@ -10231,55 +10425,55 @@
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ=="
},
"node_modules/@vue/compiler-core": {
- "version": "3.4.38",
- "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.38.tgz",
- "integrity": "sha512-8IQOTCWnLFqfHzOGm9+P8OPSEDukgg3Huc92qSG49if/xI2SAwLHQO2qaPQbjCWPBcQoO1WYfXfTACUrWV3c5A==",
+ "version": "3.5.6",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.6.tgz",
+ "integrity": "sha512-r+gNu6K4lrvaQLQGmf+1gc41p3FO2OUJyWmNqaIITaJU6YFiV5PtQSFZt8jfztYyARwqhoCayjprC7KMvT3nRA==",
"dependencies": {
- "@babel/parser": "^7.24.7",
- "@vue/shared": "3.4.38",
+ "@babel/parser": "^7.25.3",
+ "@vue/shared": "3.5.6",
"entities": "^4.5.0",
"estree-walker": "^2.0.2",
"source-map-js": "^1.2.0"
}
},
"node_modules/@vue/compiler-dom": {
- "version": "3.4.38",
- "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.38.tgz",
- "integrity": "sha512-Osc/c7ABsHXTsETLgykcOwIxFktHfGSUDkb05V61rocEfsFDcjDLH/IHJSNJP+/Sv9KeN2Lx1V6McZzlSb9EhQ==",
+ "version": "3.5.6",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.6.tgz",
+ "integrity": "sha512-xRXqxDrIqK8v8sSScpistyYH0qYqxakpsIvqMD2e5sV/PXQ1mTwtXp4k42yHK06KXxKSmitop9e45Ui/3BrTEw==",
"dependencies": {
- "@vue/compiler-core": "3.4.38",
- "@vue/shared": "3.4.38"
+ "@vue/compiler-core": "3.5.6",
+ "@vue/shared": "3.5.6"
}
},
"node_modules/@vue/compiler-sfc": {
- "version": "3.4.38",
- "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.38.tgz",
- "integrity": "sha512-s5QfZ+9PzPh3T5H4hsQDJtI8x7zdJaew/dCGgqZ2630XdzaZ3AD8xGZfBqpT8oaD/p2eedd+pL8tD5vvt5ZYJQ==",
- "dependencies": {
- "@babel/parser": "^7.24.7",
- "@vue/compiler-core": "3.4.38",
- "@vue/compiler-dom": "3.4.38",
- "@vue/compiler-ssr": "3.4.38",
- "@vue/shared": "3.4.38",
+ "version": "3.5.6",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.6.tgz",
+ "integrity": "sha512-pjWJ8Kj9TDHlbF5LywjVso+BIxCY5wVOLhkEXRhuCHDxPFIeX1zaFefKs8RYoHvkSMqRWt93a0f2gNJVJixHwg==",
+ "dependencies": {
+ "@babel/parser": "^7.25.3",
+ "@vue/compiler-core": "3.5.6",
+ "@vue/compiler-dom": "3.5.6",
+ "@vue/compiler-ssr": "3.5.6",
+ "@vue/shared": "3.5.6",
"estree-walker": "^2.0.2",
- "magic-string": "^0.30.10",
- "postcss": "^8.4.40",
+ "magic-string": "^0.30.11",
+ "postcss": "^8.4.47",
"source-map-js": "^1.2.0"
}
},
"node_modules/@vue/compiler-ssr": {
- "version": "3.4.38",
- "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.38.tgz",
- "integrity": "sha512-YXznKFQ8dxYpAz9zLuVvfcXhc31FSPFDcqr0kyujbOwNhlmaNvL2QfIy+RZeJgSn5Fk54CWoEUeW+NVBAogGaw==",
+ "version": "3.5.6",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.6.tgz",
+ "integrity": "sha512-VpWbaZrEOCqnmqjE83xdwegtr5qO/2OPUC6veWgvNqTJ3bYysz6vY3VqMuOijubuUYPRpG3OOKIh9TD0Stxb9A==",
"dependencies": {
- "@vue/compiler-dom": "3.4.38",
- "@vue/shared": "3.4.38"
+ "@vue/compiler-dom": "3.5.6",
+ "@vue/shared": "3.5.6"
}
},
"node_modules/@vue/shared": {
- "version": "3.4.38",
- "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.38.tgz",
- "integrity": "sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw=="
+ "version": "3.5.6",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.6.tgz",
+ "integrity": "sha512-eidH0HInnL39z6wAt6SFIwBrvGOpDWsDxlw3rCgo1B+CQ1781WzQUSU3YjxgdkcJo9Q8S6LmXTkvI+cLHGkQfA=="
},
"node_modules/@webassemblyjs/ast": {
"version": "1.12.1",
@@ -10538,9 +10732,9 @@
}
},
"node_modules/acorn-walk": {
- "version": "8.3.3",
- "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz",
- "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==",
+ "version": "8.3.4",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
+ "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
"dev": true,
"dependencies": {
"acorn": "^8.11.0"
@@ -10550,9 +10744,9 @@
}
},
"node_modules/adm-zip": {
- "version": "0.5.15",
- "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.15.tgz",
- "integrity": "sha512-jYPWSeOA8EFoZnucrKCNihqBjoEGQSU4HKgHYQgKNEQ0pQF9a/DYuo/+fAxY76k4qe75LUlLWpAM1QWcBMTOKw==",
+ "version": "0.5.16",
+ "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz",
+ "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==",
"engines": {
"node": ">=12.0"
}
@@ -11048,6 +11242,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/await-to-js": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/await-to-js/-/await-to-js-3.0.0.tgz",
+ "integrity": "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
@@ -11057,14 +11259,14 @@
}
},
"node_modules/aws4": {
- "version": "1.13.1",
- "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.1.tgz",
- "integrity": "sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA=="
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz",
+ "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw=="
},
"node_modules/axios": {
- "version": "1.7.5",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz",
- "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==",
+ "version": "1.7.7",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
+ "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
@@ -11088,9 +11290,9 @@
}
},
"node_modules/babel-loader": {
- "version": "9.1.3",
- "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz",
- "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==",
+ "version": "9.2.1",
+ "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz",
+ "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==",
"dependencies": {
"find-cache-dir": "^4.0.0",
"schema-utils": "^4.0.0"
@@ -11351,10 +11553,10 @@
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
},
- "node_modules/bmp-js": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
- "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw=="
+ "node_modules/bmp-ts": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/bmp-ts/-/bmp-ts-1.0.9.tgz",
+ "integrity": "sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw=="
},
"node_modules/bn.js": {
"version": "4.12.0",
@@ -11362,9 +11564,9 @@
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
},
"node_modules/body-parser": {
- "version": "1.20.2",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
- "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
+ "version": "1.20.3",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
+ "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
"dependencies": {
"bytes": "3.1.2",
"content-type": "~1.0.5",
@@ -11374,7 +11576,7 @@
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
- "qs": "6.11.0",
+ "qs": "6.13.0",
"raw-body": "2.5.2",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
@@ -11458,9 +11660,9 @@
}
},
"node_modules/browndash-components": {
- "version": "0.1.45",
- "resolved": "https://registry.npmjs.org/browndash-components/-/browndash-components-0.1.45.tgz",
- "integrity": "sha512-A2/3SikcA1kntY8jajwWJjnRGVRP9+DheaOMh9fAdgiQrdMZVMty+nUasbXk9HjyjkMfAUAkGvCR+SS28QL/zA==",
+ "version": "0.1.47",
+ "resolved": "https://registry.npmjs.org/browndash-components/-/browndash-components-0.1.47.tgz",
+ "integrity": "sha512-562nWku81I1wccgEQbMU/30+RP/81sxsIGoPGLH7Otm9TdrHXWgW8yJS4tzBPXBF03Q2AX8DyQusi6T0LSc7Mw==",
"dependencies": {
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
@@ -11479,6 +11681,116 @@
"integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==",
"peer": true
},
+ "node_modules/browndash-components/node_modules/@mui/core-downloads-tracker": {
+ "version": "5.16.7",
+ "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.7.tgz",
+ "integrity": "sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ }
+ },
+ "node_modules/browndash-components/node_modules/@mui/material": {
+ "version": "5.16.7",
+ "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.7.tgz",
+ "integrity": "sha512-cwwVQxBhK60OIOqZOVLFt55t01zmarKJiJUWbk0+8s/Ix5IaUzAShqlJchxsIQ4mSrWqgcKCCXKtIlG5H+/Jmg==",
+ "dependencies": {
+ "@babel/runtime": "^7.23.9",
+ "@mui/core-downloads-tracker": "^5.16.7",
+ "@mui/system": "^5.16.7",
+ "@mui/types": "^7.2.15",
+ "@mui/utils": "^5.16.6",
+ "@popperjs/core": "^2.11.8",
+ "@types/react-transition-group": "^4.4.10",
+ "clsx": "^2.1.0",
+ "csstype": "^3.1.3",
+ "prop-types": "^15.8.1",
+ "react-is": "^18.3.1",
+ "react-transition-group": "^4.4.5"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.5.0",
+ "@emotion/styled": "^11.3.0",
+ "@types/react": "^17.0.0 || ^18.0.0",
+ "react": "^17.0.0 || ^18.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/browndash-components/node_modules/@mui/private-theming": {
+ "version": "5.16.6",
+ "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz",
+ "integrity": "sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==",
+ "dependencies": {
+ "@babel/runtime": "^7.23.9",
+ "@mui/utils": "^5.16.6",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0",
+ "react": "^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/browndash-components/node_modules/@mui/styled-engine": {
+ "version": "5.16.6",
+ "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz",
+ "integrity": "sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==",
+ "dependencies": {
+ "@babel/runtime": "^7.23.9",
+ "@emotion/cache": "^11.11.0",
+ "csstype": "^3.1.3",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.4.1",
+ "@emotion/styled": "^11.3.0",
+ "react": "^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ }
+ }
+ },
"node_modules/browndash-components/node_modules/@mui/styled-engine-sc": {
"version": "5.14.12",
"resolved": "https://registry.npmjs.org/@mui/styled-engine-sc/-/styled-engine-sc-5.14.12.tgz",
@@ -11505,6 +11817,74 @@
}
}
},
+ "node_modules/browndash-components/node_modules/@mui/system": {
+ "version": "5.16.7",
+ "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.7.tgz",
+ "integrity": "sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA==",
+ "dependencies": {
+ "@babel/runtime": "^7.23.9",
+ "@mui/private-theming": "^5.16.6",
+ "@mui/styled-engine": "^5.16.6",
+ "@mui/types": "^7.2.15",
+ "@mui/utils": "^5.16.6",
+ "clsx": "^2.1.0",
+ "csstype": "^3.1.3",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.5.0",
+ "@emotion/styled": "^11.3.0",
+ "@types/react": "^17.0.0 || ^18.0.0",
+ "react": "^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/browndash-components/node_modules/@mui/utils": {
+ "version": "5.16.6",
+ "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz",
+ "integrity": "sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA==",
+ "dependencies": {
+ "@babel/runtime": "^7.23.9",
+ "@mui/types": "^7.2.15",
+ "@types/prop-types": "^15.7.12",
+ "clsx": "^2.1.1",
+ "prop-types": "^15.8.1",
+ "react-is": "^18.3.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0",
+ "react": "^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/browndash-components/node_modules/npm": {
"version": "9.9.3",
"resolved": "https://registry.npmjs.org/npm/-/npm-9.9.3.tgz",
@@ -11581,6 +11961,13 @@
"which",
"write-file-atomic"
],
+ "workspaces": [
+ "docs",
+ "smoke-tests",
+ "mock-globals",
+ "mock-registry",
+ "workspaces/*"
+ ],
"dependencies": {
"@isaacs/string-locale-compare": "^1.1.0",
"@npmcli/arborist": "^6.5.0",
@@ -14615,9 +15002,9 @@
}
},
"node_modules/buffer": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
- "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
@@ -14634,7 +15021,7 @@
],
"dependencies": {
"base64-js": "^1.3.1",
- "ieee754": "^1.1.13"
+ "ieee754": "^1.2.1"
}
},
"node_modules/buffer-crc32": {
@@ -14645,14 +15032,6 @@
"node": ">=8.0.0"
}
},
- "node_modules/buffer-equal": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz",
- "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==",
- "engines": {
- "node": ">=0.4.0"
- }
- },
"node_modules/buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
@@ -14807,9 +15186,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001653",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz",
- "integrity": "sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==",
+ "version": "1.0.30001660",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz",
+ "integrity": "sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==",
"funding": [
{
"type": "opencollective",
@@ -14853,14 +15232,6 @@
"url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/centra": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/centra/-/centra-2.7.0.tgz",
- "integrity": "sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==",
- "dependencies": {
- "follow-redirects": "^1.15.6"
- }
- },
"node_modules/chai": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz",
@@ -15504,6 +15875,11 @@
"quickselect": "^2.0.0"
}
},
+ "node_modules/confbox": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz",
+ "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA=="
+ },
"node_modules/connect-flash": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/connect-flash/-/connect-flash-0.1.1.tgz",
@@ -15929,23 +16305,17 @@
}
},
"node_modules/cssstyle": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz",
- "integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz",
+ "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==",
"dev": true,
"dependencies": {
- "rrweb-cssom": "^0.6.0"
+ "rrweb-cssom": "^0.7.1"
},
"engines": {
"node": ">=18"
}
},
- "node_modules/cssstyle/node_modules/rrweb-cssom": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz",
- "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==",
- "dev": true
- },
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -16010,6 +16380,30 @@
"cytoscape": "^3.2.0"
}
},
+ "node_modules/cytoscape-fcose": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz",
+ "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==",
+ "dependencies": {
+ "cose-base": "^2.2.0"
+ },
+ "peerDependencies": {
+ "cytoscape": "^3.2.0"
+ }
+ },
+ "node_modules/cytoscape-fcose/node_modules/cose-base": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz",
+ "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==",
+ "dependencies": {
+ "layout-base": "^2.0.0"
+ }
+ },
+ "node_modules/cytoscape-fcose/node_modules/layout-base": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz",
+ "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg=="
+ },
"node_modules/D": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/D/-/D-1.0.0.tgz",
@@ -16557,11 +16951,11 @@
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="
},
"node_modules/debug": {
- "version": "4.3.6",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
- "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
+ "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"dependencies": {
- "ms": "2.1.2"
+ "ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
@@ -16740,18 +17134,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/default-gateway": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz",
- "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==",
- "dev": true,
- "dependencies": {
- "execa": "^5.0.0"
- },
- "engines": {
- "node": ">= 10"
- }
- },
"node_modules/defer-to-connect": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
@@ -17023,11 +17405,6 @@
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
- "node_modules/dom-walk": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
- "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
- },
"node_modules/domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
@@ -17138,9 +17515,9 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
},
"node_modules/electron-to-chromium": {
- "version": "1.5.13",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz",
- "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q=="
+ "version": "1.5.24",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.24.tgz",
+ "integrity": "sha512-0x0wLCmpdKFCi9ulhvYZebgcPmHTkFVUfU2wzDykadkslKwT4oAmDTHEKLnlrDsMGZe4B+ksn8quZfZjYsBetA=="
},
"node_modules/emoji-regex": {
"version": "9.2.2",
@@ -17156,9 +17533,9 @@
}
},
"node_modules/encodeurl": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
- "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"engines": {
"node": ">= 0.8"
}
@@ -17267,9 +17644,9 @@
}
},
"node_modules/envinfo": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz",
- "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==",
+ "version": "7.14.0",
+ "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz",
+ "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==",
"bin": {
"envinfo": "dist/cli.js"
},
@@ -17452,9 +17829,9 @@
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
},
"node_modules/escalade": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
- "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"engines": {
"node": ">=6"
}
@@ -17476,16 +17853,17 @@
}
},
"node_modules/eslint": {
- "version": "9.9.1",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.1.tgz",
- "integrity": "sha512-dHvhrbfr4xFQ9/dq+jcVneZMyRYLjggWjk6RVsIiHsP8Rz6yZ8LvZ//iU4TrZF+SXWG+JkNF2OyiZRvzgRDqMg==",
+ "version": "9.10.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.10.0.tgz",
+ "integrity": "sha512-Y4D0IgtBZfOcOUAIQTSXBKoNGfY0REGqHJG6+Q81vNippW5YlKjHFj4soMxamKK1NXHUWuBZTLdU3Km+L/pcHw==",
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.11.0",
"@eslint/config-array": "^0.18.0",
"@eslint/eslintrc": "^3.1.0",
- "@eslint/js": "9.9.1",
+ "@eslint/js": "9.10.0",
+ "@eslint/plugin-kit": "^0.1.0",
"@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.3.0",
"@nodelib/fs.walk": "^1.2.8",
@@ -17508,7 +17886,6 @@
"is-glob": "^4.0.0",
"is-path-inside": "^3.0.3",
"json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
"lodash.merge": "^4.6.2",
"minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
@@ -17535,9 +17912,9 @@
}
},
"node_modules/eslint-plugin-react": {
- "version": "7.35.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.0.tgz",
- "integrity": "sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==",
+ "version": "7.36.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz",
+ "integrity": "sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -17856,47 +18233,6 @@
"node": ">=0.8.x"
}
},
- "node_modules/execa": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
- "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
- "dev": true,
- "dependencies": {
- "cross-spawn": "^7.0.3",
- "get-stream": "^6.0.0",
- "human-signals": "^2.1.0",
- "is-stream": "^2.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^4.0.1",
- "onetime": "^5.1.2",
- "signal-exit": "^3.0.3",
- "strip-final-newline": "^2.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sindresorhus/execa?sponsor=1"
- }
- },
- "node_modules/execa/node_modules/get-stream": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
- "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/execa/node_modules/signal-exit": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
- "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
- "dev": true
- },
"node_modules/exif": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/exif/-/exif-0.6.0.tgz",
@@ -17940,36 +18276,36 @@
}
},
"node_modules/express": {
- "version": "4.19.2",
- "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
- "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz",
+ "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
- "body-parser": "1.20.2",
+ "body-parser": "1.20.3",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "0.6.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
- "encodeurl": "~1.0.2",
+ "encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
- "finalhandler": "1.2.0",
+ "finalhandler": "1.3.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
- "merge-descriptors": "1.0.1",
+ "merge-descriptors": "1.0.3",
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
- "path-to-regexp": "0.1.7",
+ "path-to-regexp": "0.1.10",
"proxy-addr": "~2.0.7",
- "qs": "6.11.0",
+ "qs": "6.13.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
- "send": "0.18.0",
- "serve-static": "1.15.0",
+ "send": "0.19.0",
+ "serve-static": "1.16.2",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"type-is": "~1.6.18",
@@ -18085,9 +18421,9 @@
}
},
"node_modules/extract-colors": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/extract-colors/-/extract-colors-4.0.6.tgz",
- "integrity": "sha512-U+pYyQKXCSHOmtZPIEJBGLJjLDiqS+oOub2ILA3a7UGt9+IvZvwAN3hOPFjUgT+gX/apSBwP5vBgnKMlV0fy8Q=="
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/extract-colors/-/extract-colors-4.0.8.tgz",
+ "integrity": "sha512-XW6Ee9bgdx4Z9GchZm2likadze+BjQG1orkSyfxjd9znvxxtc7UBHf//1lFMtQm+lDusO3Fz8giaok0LWyflOA=="
},
"node_modules/extsprintf": {
"version": "1.3.0",
@@ -18131,6 +18467,7 @@
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
@@ -18147,6 +18484,7 @@
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
},
@@ -18170,9 +18508,9 @@
"integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw=="
},
"node_modules/fast-xml-parser": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz",
- "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==",
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz",
+ "integrity": "sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==",
"funding": [
{
"type": "github",
@@ -18332,12 +18670,12 @@
}
},
"node_modules/finalhandler": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
- "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
+ "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"dependencies": {
"debug": "2.6.9",
- "encodeurl": "~1.0.2",
+ "encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
@@ -18458,9 +18796,9 @@
"integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw=="
},
"node_modules/flexlayout-react": {
- "version": "0.7.15",
- "resolved": "https://registry.npmjs.org/flexlayout-react/-/flexlayout-react-0.7.15.tgz",
- "integrity": "sha512-ydTMdEoQO5BniylxVkSxa59rEY0+96lqqRII+QK+yq6028eHywPuxZawt4g45y5pMb9ptP4N9HPAQXAFsxwowQ==",
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/flexlayout-react/-/flexlayout-react-0.8.0.tgz",
+ "integrity": "sha512-nTkEOxVw438/6ugzKb0nBFRzJkWPYOgx8laGhDmTsXMuJQMEEC4dxyRSswcjt8IWsCKl8zSQHlsxSG+PrdJENQ==",
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
@@ -18495,9 +18833,9 @@
}
},
"node_modules/follow-redirects": {
- "version": "1.15.6",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
- "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
+ "version": "1.15.9",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
+ "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
@@ -18873,6 +19211,19 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
+ "node_modules/fullcalendar": {
+ "version": "6.1.15",
+ "resolved": "https://registry.npmjs.org/fullcalendar/-/fullcalendar-6.1.15.tgz",
+ "integrity": "sha512-CFnh1yswjRh9puJVDk8VGwTlyZ6eXxr4qLI7QCA0+bozyAm+BluP1US5mOtgk0gEq23nQxGSNDoBvAraz++saQ==",
+ "dependencies": {
+ "@fullcalendar/core": "~6.1.15",
+ "@fullcalendar/daygrid": "~6.1.15",
+ "@fullcalendar/interaction": "~6.1.15",
+ "@fullcalendar/list": "~6.1.15",
+ "@fullcalendar/multimonth": "~6.1.15",
+ "@fullcalendar/timegrid": "~6.1.15"
+ }
+ },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -19282,15 +19633,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/global": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
- "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
- "dependencies": {
- "min-document": "^2.19.0",
- "process": "^0.11.10"
- }
- },
"node_modules/global-modules": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
@@ -19365,9 +19707,9 @@
"integrity": "sha512-sIVQCiRWOymHbVD1Aw/T9/ijbPYAVGBlgGYd1N9MRKfcyBNSpjr87Vg9nSHm+RCT8ELrvK8IJYJV0QRJuVUkCQ=="
},
"node_modules/google-auth-library": {
- "version": "9.14.0",
- "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.14.0.tgz",
- "integrity": "sha512-Y/eq+RWVs55Io/anIsm24sDS8X79Tq948zVLGaa7+KlJYYqaGwp1YI37w48nzrNi12RgnzMrQD4NzdmCowT90g==",
+ "version": "9.14.1",
+ "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.14.1.tgz",
+ "integrity": "sha512-Rj+PMjoNFGFTmtItH7gHfbHpGVSb3vmnGK3nwNBqxQF9NoBpttSZI/rc0WiM63ma2uGDQtYEkMHkK9U6937NiA==",
"dependencies": {
"base64-js": "^1.3.0",
"ecdsa-sig-formatter": "^1.0.11",
@@ -19393,9 +19735,9 @@
}
},
"node_modules/googleapis": {
- "version": "142.0.0",
- "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-142.0.0.tgz",
- "integrity": "sha512-LsU1ynez4/KNPwnFMSDI93pBEsETNdQPCrT3kz2qgiNg5H2pW4dKW+1VmENMkZ4u9lMxA89nnXD3nqWBJ0rruQ==",
+ "version": "144.0.0",
+ "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-144.0.0.tgz",
+ "integrity": "sha512-ELcWOXtJxjPX4vsKMh+7V+jZvgPwYMlEhQFiu2sa9Qmt5veX8nwXPksOWGGN6Zk4xCiLygUyaz7xGtcMO+Onxw==",
"dependencies": {
"google-auth-library": "^9.0.0",
"googleapis-common": "^7.0.0"
@@ -19489,7 +19831,8 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/grid-index": {
"version": "1.1.0",
@@ -19635,9 +19978,9 @@
}
},
"node_modules/hast-util-from-html": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.2.tgz",
- "integrity": "sha512-HwOHwxdt2zC5KQ/CNoybBntRook2zJvfZE/u5/Ap7aLPe22bDqen7KwGkOqOyzL5zIqKwiYX/OTtE0FWgr6XXA==",
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz",
+ "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==",
"dependencies": {
"@types/hast": "^3.0.0",
"devlop": "^1.1.0",
@@ -20206,15 +20549,6 @@
"node": ">= 14"
}
},
- "node_modules/human-signals": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
- "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
- "dev": true,
- "engines": {
- "node": ">=10.17.0"
- }
- },
"node_modules/humanize-ms": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
@@ -20437,7 +20771,6 @@
"version": "0.3.5",
"resolved": "git+ssh://git@github.com/netroy/image-size.git#da2c863807a3e9602617bdd357b0de3ab4a064c1",
"integrity": "sha512-bOV/01RFEAMM7OJU4alHoipipEYAdVk1W9rto2aN1ZnEZsZ1A1OCVJJ2iMaaJIKidVXGZNbP9knmW/3wWTZ4/Q==",
- "license": "MIT",
"bin": {
"image-size": "bin/image-size"
},
@@ -20625,9 +20958,9 @@
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
},
"node_modules/inline-style-parser": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.3.tgz",
- "integrity": "sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g=="
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz",
+ "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="
},
"node_modules/inspect-function": {
"version": "0.3.4",
@@ -20747,6 +21080,14 @@
"inspect-function": "^0.3.1"
}
},
+ "node_modules/install": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/install/-/install-0.13.0.tgz",
+ "integrity": "sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/internal-slot": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
@@ -21081,11 +21422,6 @@
"node": ">=8"
}
},
- "node_modules/is-function": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz",
- "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ=="
- },
"node_modules/is-generator-function": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
@@ -21439,15 +21775,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/isomorphic-fetch": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz",
- "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==",
- "dependencies": {
- "node-fetch": "^2.6.1",
- "whatwg-fetch": "^3.4.1"
- }
- },
"node_modules/isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
@@ -21606,21 +21933,42 @@
}
},
"node_modules/jimp": {
- "version": "0.22.12",
- "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.22.12.tgz",
- "integrity": "sha512-R5jZaYDnfkxKJy1dwLpj/7cvyjxiclxU3F4TrI/J4j2rS0niq6YDUMoPn5hs8GDpO+OZGo7Ky057CRtWesyhfg==",
- "dependencies": {
- "@jimp/custom": "^0.22.12",
- "@jimp/plugins": "^0.22.12",
- "@jimp/types": "^0.22.12",
- "regenerator-runtime": "^0.13.3"
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/jimp/-/jimp-1.6.0.tgz",
+ "integrity": "sha512-YcwCHw1kiqEeI5xRpDlPPBGL2EOpBKLwO4yIBJcXWHPj5PnA5urGq0jbyhM5KoNpypQ6VboSoxc9D8HyfvngSg==",
+ "dependencies": {
+ "@jimp/core": "1.6.0",
+ "@jimp/diff": "1.6.0",
+ "@jimp/js-bmp": "1.6.0",
+ "@jimp/js-gif": "1.6.0",
+ "@jimp/js-jpeg": "1.6.0",
+ "@jimp/js-png": "1.6.0",
+ "@jimp/js-tiff": "1.6.0",
+ "@jimp/plugin-blit": "1.6.0",
+ "@jimp/plugin-blur": "1.6.0",
+ "@jimp/plugin-circle": "1.6.0",
+ "@jimp/plugin-color": "1.6.0",
+ "@jimp/plugin-contain": "1.6.0",
+ "@jimp/plugin-cover": "1.6.0",
+ "@jimp/plugin-crop": "1.6.0",
+ "@jimp/plugin-displace": "1.6.0",
+ "@jimp/plugin-dither": "1.6.0",
+ "@jimp/plugin-fisheye": "1.6.0",
+ "@jimp/plugin-flip": "1.6.0",
+ "@jimp/plugin-hash": "1.6.0",
+ "@jimp/plugin-mask": "1.6.0",
+ "@jimp/plugin-print": "1.6.0",
+ "@jimp/plugin-quantize": "1.6.0",
+ "@jimp/plugin-resize": "1.6.0",
+ "@jimp/plugin-rotate": "1.6.0",
+ "@jimp/plugin-threshold": "1.6.0",
+ "@jimp/types": "1.6.0",
+ "@jimp/utils": "1.6.0"
+ },
+ "engines": {
+ "node": ">=18"
}
},
- "node_modules/jimp/node_modules/regenerator-runtime": {
- "version": "0.13.11",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
- "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
- },
"node_modules/jpeg-autorotate": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/jpeg-autorotate/-/jpeg-autorotate-9.0.0.tgz",
@@ -21689,9 +22037,9 @@
"integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
},
"node_modules/js-datepicker": {
- "version": "5.18.2",
- "resolved": "https://registry.npmjs.org/js-datepicker/-/js-datepicker-5.18.2.tgz",
- "integrity": "sha512-lBh5tIwb1ewDVlNHuwczoLiMhTFWnGYuHSA7ONAPKyMeofIFZDFGeOZ71UTY/Mk2evJJt+L66ec/RiXUy8XzEg=="
+ "version": "5.18.3",
+ "resolved": "https://registry.npmjs.org/js-datepicker/-/js-datepicker-5.18.3.tgz",
+ "integrity": "sha512-M1+UKeRkLT0p04JhnSpNugveFSfy6VfEeNTyAyFef6unKIqQx4oQqx66lsBi0FRKHb4HtQsmJ8V4L4SPj1lbRQ=="
},
"node_modules/js-stringify": {
"version": "1.0.2",
@@ -21760,6 +22108,30 @@
}
}
},
+ "node_modules/jsdom/node_modules/tough-cookie": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
+ "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
+ "dev": true,
+ "dependencies": {
+ "psl": "^1.1.33",
+ "punycode": "^2.1.1",
+ "universalify": "^0.2.0",
+ "url-parse": "^1.5.3"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/jsdom/node_modules/universalify": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
+ "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
"node_modules/jsesc": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
@@ -22025,6 +22397,11 @@
"graceful-fs": "^4.1.9"
}
},
+ "node_modules/kolorist": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz",
+ "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ=="
+ },
"node_modules/kruptein": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/kruptein/-/kruptein-3.0.7.tgz",
@@ -22103,9 +22480,9 @@
}
},
"node_modules/launch-editor": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.1.tgz",
- "integrity": "sha512-elBx2l/tp9z99X5H/qev8uyDywVh0VXAwEbjk8kJhnc5grOFkGh7aW6q55me9xnYbss261XtnUrysZ+XvGbhQA==",
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz",
+ "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==",
"dev": true,
"dependencies": {
"picocolors": "^1.0.0",
@@ -22206,21 +22583,6 @@
"uc.micro": "^2.0.0"
}
},
- "node_modules/load-bmfont": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.2.tgz",
- "integrity": "sha512-qElWkmjW9Oq1F9EI5Gt7aD9zcdHb9spJCW1L/dmPf7KzCCEJxq8nhHz5eCgI9aMf7vrG/wyaCqdsI+Iy9ZTlog==",
- "dependencies": {
- "buffer-equal": "0.0.1",
- "mime": "^1.3.4",
- "parse-bmfont-ascii": "^1.0.3",
- "parse-bmfont-binary": "^1.0.5",
- "parse-bmfont-xml": "^1.1.4",
- "phin": "^3.7.1",
- "xhr": "^2.0.1",
- "xtend": "^4.0.0"
- }
- },
"node_modules/loader-runner": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
@@ -22242,6 +22604,21 @@
"node": ">=8.9.0"
}
},
+ "node_modules/local-pkg": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz",
+ "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==",
+ "dependencies": {
+ "mlly": "^1.4.2",
+ "pkg-types": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -22537,6 +22914,10 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-3.6.0.tgz",
"integrity": "sha512-xjYHHIJDh6haYcKY+/9jh1eywwYfIOWCgT5Fowj4JriZexx/oOtg2S7BQDMZtpFyg9IN4VLCysmUWxY0pFNRWA==",
+ "workspaces": [
+ "src/style-spec",
+ "test/build/typings"
+ ],
"dependencies": {
"@mapbox/jsonlint-lines-primitives": "^2.0.2",
"@mapbox/mapbox-gl-supported": "^3.0.0",
@@ -22830,9 +23211,9 @@
}
},
"node_modules/mdast-util-mdx-expression": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz",
- "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz",
+ "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==",
"dependencies": {
"@types/estree-jsx": "^1.0.0",
"@types/hast": "^3.0.0",
@@ -22993,9 +23374,12 @@
}
},
"node_modules/merge-descriptors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
- "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+ "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
},
"node_modules/merge-stream": {
"version": "2.0.0",
@@ -23007,19 +23391,22 @@
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 8"
}
},
"node_modules/mermaid": {
- "version": "11.0.2",
- "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.0.2.tgz",
- "integrity": "sha512-KFM1o560odBHvXTTSx47ne/SE4aJKb2GbysHAVdQafIJtB6O3c0K4F+v3nC+zqS6CJhk7sXaagectNrTG+ARDw==",
+ "version": "11.2.1",
+ "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.2.1.tgz",
+ "integrity": "sha512-F8TEaLVVyxTUmvKswVFyOkjPrlJA5h5vNR1f7ZnSWSpqxgEZG1hggtn/QCa7znC28bhlcrNh10qYaIiill7q4A==",
"dependencies": {
"@braintree/sanitize-url": "^7.0.1",
- "@mermaid-js/parser": "^0.2.0",
+ "@iconify/utils": "^2.1.32",
+ "@mermaid-js/parser": "^0.3.0",
"cytoscape": "^3.29.2",
"cytoscape-cose-bilkent": "^4.1.0",
+ "cytoscape-fcose": "^2.2.0",
"d3": "^7.9.0",
"d3-sankey": "^0.12.3",
"dagre-d3-es": "7.0.10",
@@ -23631,14 +24018,14 @@
}
},
"node_modules/mime": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
- "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
+ "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
"bin": {
"mime": "cli.js"
},
"engines": {
- "node": ">=4"
+ "node": ">=10.0.0"
}
},
"node_modules/mime-db": {
@@ -23660,15 +24047,6 @@
"node": ">= 0.6"
}
},
- "node_modules/mimic-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/mimic-response": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz",
@@ -23680,14 +24058,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/min-document": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
- "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==",
- "dependencies": {
- "dom-walk": "^0.1.0"
- }
- },
"node_modules/minimalistic-assert": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
@@ -23767,15 +24137,26 @@
"node": ">=10"
}
},
+ "node_modules/mlly": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz",
+ "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==",
+ "dependencies": {
+ "acorn": "^8.11.3",
+ "pathe": "^1.1.2",
+ "pkg-types": "^1.1.1",
+ "ufo": "^1.5.3"
+ }
+ },
"node_modules/mobile-detect": {
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/mobile-detect/-/mobile-detect-1.4.5.tgz",
"integrity": "sha512-yc0LhH6tItlvfLBugVUEtgawwFU2sIe+cSdmRJJCTMZ5GEJyLxNyC/NIOAOGk67Fa8GNpOttO3Xz/1bHpXFD/g=="
},
"node_modules/mobx": {
- "version": "6.13.1",
- "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.13.1.tgz",
- "integrity": "sha512-ekLRxgjWJr8hVxj9ZKuClPwM/iHckx3euIJ3Np7zLVNtqJvfbbq7l370W/98C8EabdQ1pB5Jd3BbDWxJPNnaOg==",
+ "version": "6.13.2",
+ "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.13.2.tgz",
+ "integrity": "sha512-GIubI2qf+P6lG6rSEG0T2pg3jV9/0+O0ncF09+0umRe75+Cbnh1KNLM1GvbTY9RSc7QuU+LcPNZfxDY8B+3XRg==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mobx"
@@ -23931,12 +24312,6 @@
"node": ">=10"
}
},
- "node_modules/mocha/node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true
- },
"node_modules/mocha/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
@@ -23953,9 +24328,9 @@
}
},
"node_modules/mongodb": {
- "version": "6.8.0",
- "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.8.0.tgz",
- "integrity": "sha512-HGQ9NWDle5WvwMnrvUxsFYPd3JEbqD3RgABHBQRuoCEND0qzhsd0iH5ypHsf1eJ+sXmvmyKpP+FLOKY8Il7jMw==",
+ "version": "6.9.0",
+ "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.9.0.tgz",
+ "integrity": "sha512-UMopBVx1LmEUbW/QE0Hw18u583PEDVQmUmVzzBRH0o/xtE9DBRA5ZYLOjpLIa03i8FXjzvQECJcqoMvCXftTUA==",
"dependencies": {
"@mongodb-js/saslprep": "^1.1.5",
"bson": "^6.7.0",
@@ -24030,13 +24405,13 @@
}
},
"node_modules/mongoose": {
- "version": "8.5.4",
- "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.5.4.tgz",
- "integrity": "sha512-nG3eehhWf9l1q80WuHvp5DV+4xDNFpDWLE5ZgcFD5tslUV2USJ56ogun8gaZ62MKAocJnoStjAdno08b8U57hg==",
+ "version": "8.6.3",
+ "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.6.3.tgz",
+ "integrity": "sha512-++yRmm7hjMbqVA/8WeiygTnEfrFbiy+OBjQi49GFJIvCQuSYE56myyQWo4j5hbpcHjhHQU8NukMNGTwAWFWjIw==",
"dependencies": {
"bson": "^6.7.0",
"kareem": "2.6.3",
- "mongodb": "6.7.0",
+ "mongodb": "6.8.0",
"mpath": "0.9.0",
"mquery": "5.0.0",
"ms": "2.1.3",
@@ -24051,9 +24426,9 @@
}
},
"node_modules/mongoose/node_modules/mongodb": {
- "version": "6.7.0",
- "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.7.0.tgz",
- "integrity": "sha512-TMKyHdtMcO0fYBNORiYdmM25ijsHs+Njs963r4Tro4OQZzqYigAzYQouwWRg4OIaiLRUEGUh/1UAcH5lxdSLIA==",
+ "version": "6.8.0",
+ "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.8.0.tgz",
+ "integrity": "sha512-HGQ9NWDle5WvwMnrvUxsFYPd3JEbqD3RgABHBQRuoCEND0qzhsd0iH5ypHsf1eJ+sXmvmyKpP+FLOKY8Il7jMw==",
"dependencies": {
"@mongodb-js/saslprep": "^1.1.5",
"bson": "^6.7.0",
@@ -24095,11 +24470,6 @@
}
}
},
- "node_modules/mongoose/node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
- },
"node_modules/mpath": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
@@ -24125,9 +24495,9 @@
"integrity": "sha512-hug+mpbSSKnH13rFqy3zm+XiG+QTStiDAgMTHK355TIstQE0qBkBtSJsa5YHP94AuarVX9b/4dcebdTRZ9YiEw=="
},
"node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/multicast-dns": {
"version": "7.2.5",
@@ -24364,17 +24734,17 @@
}
},
"node_modules/nodemailer": {
- "version": "6.9.14",
- "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.14.tgz",
- "integrity": "sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA==",
+ "version": "6.9.15",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.15.tgz",
+ "integrity": "sha512-AHf04ySLC6CIfuRtRiEYtGEXgRfa6INgWGluDhnxTZhHSKvrBu7lc1VVchQ0d8nPc4cFaZoPq8vkyNoZr0TpGQ==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/nodemon": {
- "version": "3.1.4",
- "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz",
- "integrity": "sha512-wjPBbFhtpJwmIeY2yP7QF+UKzPfltVGtfce1g/bB15/8vCGZj8uxD62b/b9M9/WVgme0NZudpownKN+c0plXlQ==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.5.tgz",
+ "integrity": "sha512-V5UtfYc7hjFD4SI3EzD5TR8ChAHEZ+Ns7Z5fBk8fAbTVAj+q3G+w7sHJrHxXBkVn6ApLVTljau8wfHwqmGUjMw==",
"dependencies": {
"chokidar": "^3.5.2",
"debug": "^4",
@@ -24463,9 +24833,9 @@
}
},
"node_modules/npm": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/npm/-/npm-10.8.2.tgz",
- "integrity": "sha512-x/AIjFIKRllrhcb48dqUNAAZl0ig9+qMuN91RpZo3Cb2+zuibfh+KISl6+kVVyktDz230JKc208UkQwwMqyB+w==",
+ "version": "10.8.3",
+ "resolved": "https://registry.npmjs.org/npm/-/npm-10.8.3.tgz",
+ "integrity": "sha512-0IQlyAYvVtQ7uOhDFYZCGK8kkut2nh8cpAdA9E6FvRSJaTgtZRZgNjlC5ZCct//L73ygrpY93CxXpRJDtNqPVg==",
"bundleDependencies": [
"@isaacs/string-locale-compare",
"@npmcli/arborist",
@@ -24536,6 +24906,13 @@
"which",
"write-file-atomic"
],
+ "workspaces": [
+ "docs",
+ "smoke-tests",
+ "mock-globals",
+ "mock-registry",
+ "workspaces/*"
+ ],
"dependencies": {
"@isaacs/string-locale-compare": "^1.1.0",
"@npmcli/arborist": "^7.5.4",
@@ -24549,13 +24926,13 @@
"@sigstore/tuf": "^2.3.4",
"abbrev": "^2.0.0",
"archy": "~1.0.0",
- "cacache": "^18.0.3",
+ "cacache": "^18.0.4",
"chalk": "^5.3.0",
"ci-info": "^4.0.0",
"cli-columns": "^4.0.0",
"fastest-levenshtein": "^1.0.16",
"fs-minipass": "^3.0.3",
- "glob": "^10.4.2",
+ "glob": "^10.4.5",
"graceful-fs": "^4.2.11",
"hosted-git-info": "^7.0.2",
"ini": "^4.1.3",
@@ -24564,7 +24941,7 @@
"json-parse-even-better-errors": "^3.0.2",
"libnpmaccess": "^8.0.6",
"libnpmdiff": "^6.1.4",
- "libnpmexec": "^8.1.3",
+ "libnpmexec": "^8.1.4",
"libnpmfund": "^5.0.12",
"libnpmhook": "^10.0.5",
"libnpmorg": "^6.0.6",
@@ -24578,12 +24955,12 @@
"minipass": "^7.1.1",
"minipass-pipeline": "^1.2.4",
"ms": "^2.1.2",
- "node-gyp": "^10.1.0",
+ "node-gyp": "^10.2.0",
"nopt": "^7.2.1",
"normalize-package-data": "^6.0.2",
"npm-audit-report": "^5.0.0",
"npm-install-checks": "^6.3.0",
- "npm-package-arg": "^11.0.2",
+ "npm-package-arg": "^11.0.3",
"npm-pick-manifest": "^9.1.0",
"npm-profile": "^10.0.0",
"npm-registry-fetch": "^17.1.0",
@@ -24594,7 +24971,7 @@
"proc-log": "^4.2.0",
"qrcode-terminal": "^0.12.0",
"read": "^3.0.1",
- "semver": "^7.6.2",
+ "semver": "^7.6.3",
"spdx-expression-parse": "^4.0.0",
"ssri": "^10.0.6",
"supports-color": "^9.4.0",
@@ -24614,18 +24991,6 @@
"node": "^18.17.0 || >=20.5.0"
}
},
- "node_modules/npm-run-path": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
- "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/npm/node_modules/@isaacs/cliui": {
"version": "8.0.2",
"inBundle": true,
@@ -25123,7 +25488,7 @@
}
},
"node_modules/npm/node_modules/cacache": {
- "version": "18.0.3",
+ "version": "18.0.4",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -25276,7 +25641,7 @@
}
},
"node_modules/npm/node_modules/debug": {
- "version": "4.3.5",
+ "version": "4.3.6",
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -25350,7 +25715,7 @@
}
},
"node_modules/npm/node_modules/foreground-child": {
- "version": "3.2.1",
+ "version": "3.3.0",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -25376,7 +25741,7 @@
}
},
"node_modules/npm/node_modules/glob": {
- "version": "10.4.2",
+ "version": "10.4.5",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -25390,9 +25755,6 @@
"bin": {
"glob": "dist/esm/bin.mjs"
},
- "engines": {
- "node": ">=16 || 14 >=14.18"
- },
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
@@ -25559,15 +25921,12 @@
"license": "ISC"
},
"node_modules/npm/node_modules/jackspeak": {
- "version": "3.4.0",
+ "version": "3.4.3",
"inBundle": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/cliui": "^8.0.2"
},
- "engines": {
- "node": ">=14"
- },
"funding": {
"url": "https://github.com/sponsors/isaacs"
},
@@ -25645,7 +26004,7 @@
}
},
"node_modules/npm/node_modules/libnpmexec": {
- "version": "8.1.3",
+ "version": "8.1.4",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -25770,12 +26129,9 @@
}
},
"node_modules/npm/node_modules/lru-cache": {
- "version": "10.2.2",
+ "version": "10.4.3",
"inBundle": true,
- "license": "ISC",
- "engines": {
- "node": "14 || >=16.14"
- }
+ "license": "ISC"
},
"node_modules/npm/node_modules/make-fetch-happen": {
"version": "13.0.1",
@@ -25970,7 +26326,7 @@
}
},
"node_modules/npm/node_modules/node-gyp": {
- "version": "10.1.0",
+ "version": "10.2.0",
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -25980,9 +26336,9 @@
"graceful-fs": "^4.2.6",
"make-fetch-happen": "^13.0.0",
"nopt": "^7.0.0",
- "proc-log": "^3.0.0",
+ "proc-log": "^4.1.0",
"semver": "^7.3.5",
- "tar": "^6.1.2",
+ "tar": "^6.2.1",
"which": "^4.0.0"
},
"bin": {
@@ -25992,14 +26348,6 @@
"node": "^16.14.0 || >=18.0.0"
}
},
- "node_modules/npm/node_modules/node-gyp/node_modules/proc-log": {
- "version": "3.0.0",
- "inBundle": true,
- "license": "ISC",
- "engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
- }
- },
"node_modules/npm/node_modules/nopt": {
"version": "7.2.1",
"inBundle": true,
@@ -26066,7 +26414,7 @@
}
},
"node_modules/npm/node_modules/npm-package-arg": {
- "version": "11.0.2",
+ "version": "11.0.3",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -26228,7 +26576,7 @@
}
},
"node_modules/npm/node_modules/postcss-selector-parser": {
- "version": "6.1.0",
+ "version": "6.1.2",
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -26352,7 +26700,7 @@
"optional": true
},
"node_modules/npm/node_modules/semver": {
- "version": "7.6.2",
+ "version": "7.6.3",
"inBundle": true,
"license": "ISC",
"bin": {
@@ -27072,21 +27420,6 @@
"wrappy": "1"
}
},
- "node_modules/onetime": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
- "dev": true,
- "dependencies": {
- "mimic-fn": "^2.1.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/open": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz",
@@ -27106,9 +27439,9 @@
}
},
"node_modules/openai": {
- "version": "4.56.1",
- "resolved": "https://registry.npmjs.org/openai/-/openai-4.56.1.tgz",
- "integrity": "sha512-XMsxdjrWBYgbP6EsDIwbhkQEgeyL2C41te/QrJm8kdfho22exhTUJ/cFJSmCTToam/RSOC1BlOylHvD6i/bmsA==",
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/openai/-/openai-4.62.0.tgz",
+ "integrity": "sha512-cPSsarEXoJENNwYMx/Xh/wuvnyYf8lPSR4zDVSnRvbcMHmKkDIzXhUVvPPfuI4M4T83x25gVnlW7huWEGKG+SA==",
"dependencies": {
"@types/node": "^18.11.18",
"@types/node-fetch": "^2.6.4",
@@ -27131,9 +27464,9 @@
}
},
"node_modules/openai/node_modules/@types/node": {
- "version": "18.19.46",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.46.tgz",
- "integrity": "sha512-vnRgMS7W6cKa1/0G3/DTtQYpVrZ8c0Xm6UkLaVFrb9jtcVC3okokW09Ki1Qdrj9ISokszD69nY4WDLRlvHlhAA==",
+ "version": "18.19.50",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.50.tgz",
+ "integrity": "sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==",
"dependencies": {
"undici-types": "~5.26.4"
}
@@ -27275,6 +27608,11 @@
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz",
"integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw=="
},
+ "node_modules/package-manager-detector": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.0.tgz",
+ "integrity": "sha512-E385OSk9qDcXhcM9LNSe4sdhx8a9mAPrZ4sMLW+tmxl5ZuGtPUcdFu+MPP2jbgiWAZ6Pfe5soGFMd+0Db5Vrog=="
+ },
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
@@ -27343,11 +27681,6 @@
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz",
"integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="
},
- "node_modules/parse-headers": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz",
- "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA=="
- },
"node_modules/parse-json": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
@@ -27539,9 +27872,9 @@
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
},
"node_modules/path-to-regexp": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
- "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
+ "version": "0.1.10",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
+ "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w=="
},
"node_modules/path-type": {
"version": "4.0.0",
@@ -27560,6 +27893,11 @@
"node": ">=6"
}
},
+ "node_modules/pathe": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
+ "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="
+ },
"node_modules/pathval": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz",
@@ -27623,9 +27961,9 @@
}
},
"node_modules/pdfjs-dist": {
- "version": "4.5.136",
- "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-4.5.136.tgz",
- "integrity": "sha512-V1BALcAN/FmxBEShLxoP73PlQZAZtzlaNfRbRhJrKvXzjLC5VaIlBAQUJuWP8iaYUmIdmdLHmt3E2TBglxOm3w==",
+ "version": "4.6.82",
+ "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-4.6.82.tgz",
+ "integrity": "sha512-BUOryeRFwvbLe0lOU6NhkJNuVQUp06WxlJVVCsxdmJ4y5cU3O3s3/0DunVdK1PMm7v2MUw52qKYaidhDH1Z9+w==",
"engines": {
"node": ">=18"
},
@@ -27685,21 +28023,10 @@
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
},
- "node_modules/phin": {
- "version": "3.7.1",
- "resolved": "https://registry.npmjs.org/phin/-/phin-3.7.1.tgz",
- "integrity": "sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==",
- "dependencies": {
- "centra": "^2.7.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
"node_modules/picocolors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
- "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
+ "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw=="
},
"node_modules/picomatch": {
"version": "2.3.1",
@@ -27723,22 +28050,22 @@
"integrity": "sha512-6Rtbp7criZRwedlvWbUYxqlqJoAlMvYHo2UcRWq79xZ54vZcaNHpVBOcWkX3ErT2aUA69tv+uiv4zKJbhD/Wgg=="
},
"node_modules/pixelmatch": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz",
- "integrity": "sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==",
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.3.0.tgz",
+ "integrity": "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==",
"dependencies": {
- "pngjs": "^3.0.0"
+ "pngjs": "^6.0.0"
},
"bin": {
"pixelmatch": "bin/pixelmatch"
}
},
"node_modules/pixelmatch/node_modules/pngjs": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
- "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz",
+ "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==",
"engines": {
- "node": ">=4.0.0"
+ "node": ">=12.13.0"
}
},
"node_modules/pkg-dir": {
@@ -27820,6 +28147,16 @@
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
}
},
+ "node_modules/pkg-types": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.0.tgz",
+ "integrity": "sha512-+ifYuSSqOQ8CqP4MbZA5hDpb97n3E8SVWdJe+Wms9kj745lmd3b7EZJiqvmLwAlmRfjrI7Hi5z3kdBJ93lFNPA==",
+ "dependencies": {
+ "confbox": "^0.1.7",
+ "mlly": "^1.7.1",
+ "pathe": "^1.1.2"
+ }
+ },
"node_modules/please-upgrade-node": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
@@ -27829,11 +28166,11 @@
}
},
"node_modules/pngjs": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz",
- "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz",
+ "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==",
"engines": {
- "node": ">=12.13.0"
+ "node": ">=14.19.0"
}
},
"node_modules/point-in-polygon": {
@@ -27878,9 +28215,9 @@
}
},
"node_modules/postcss": {
- "version": "8.4.41",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz",
- "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==",
+ "version": "8.4.47",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
+ "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
"funding": [
{
"type": "opencollective",
@@ -27897,8 +28234,8 @@
],
"dependencies": {
"nanoid": "^3.3.7",
- "picocolors": "^1.0.1",
- "source-map-js": "^1.2.0"
+ "picocolors": "^1.1.0",
+ "source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
@@ -28168,9 +28505,9 @@
}
},
"node_modules/prosemirror-view": {
- "version": "1.34.1",
- "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.34.1.tgz",
- "integrity": "sha512-KS2xmqrAM09h3SLu1S2pNO/ZoIP38qkTJ6KFd7+BeSfmX/ek0n5yOfGuiTZjFNTC8GOsEIUa1tHxt+2FMu3yWQ==",
+ "version": "1.34.2",
+ "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.34.2.tgz",
+ "integrity": "sha512-tPX/V2Xd70vrAGQ/V9CppJtPKnQyQMypJGlLylvdI94k6JaG+4P6fVmXPR1zc1eVTW0gq3c6zsfqwJKCRLaG9Q==",
"dependencies": {
"prosemirror-model": "^1.20.0",
"prosemirror-state": "^1.0.0",
@@ -28348,11 +28685,11 @@
}
},
"node_modules/qs": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
- "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+ "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dependencies": {
- "side-channel": "^1.0.4"
+ "side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
@@ -28389,7 +28726,8 @@
"node_modules/querystringify": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
- "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
+ "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
+ "dev": true
},
"node_modules/queue": {
"version": "6.0.2",
@@ -28807,9 +29145,9 @@
}
},
"node_modules/react-intersection-observer": {
- "version": "9.13.0",
- "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.13.0.tgz",
- "integrity": "sha512-y0UvBfjDiXqC8h0EWccyaj4dVBWMxgEx0t5RGNzQsvkfvZwugnKwxpu70StY4ivzYuMajavwUDjH4LJyIki9Lw==",
+ "version": "9.13.1",
+ "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.13.1.tgz",
+ "integrity": "sha512-tSzDaTy0qwNPLJHg8XZhlyHTgGW6drFKTtvjdL+p6um12rcnp8Z5XstE+QNBJ7c64n5o0Lj4ilUleA41bmDoMw==",
"peerDependencies": {
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
@@ -28826,15 +29164,15 @@
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
},
"node_modules/react-jsx-parser": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/react-jsx-parser/-/react-jsx-parser-2.0.0.tgz",
- "integrity": "sha512-1siP+vM47gWE+x2VTF0ano5jJPRilOf7sRIoy4dzb1FmNoDpwe3htuzgcEfvzsc7YThzwmMQNUfy4vAv1ATs2g==",
- "hasInstallScript": true,
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/react-jsx-parser/-/react-jsx-parser-2.1.0.tgz",
+ "integrity": "sha512-cGp8ceqA6j7OylsqeK2kuCGRitHpWzximsxsQyqkQO+1fwyG82Mb1l2nx9ImrfdCO6GT2kgt7C6cX9vJ46B7ow==",
"dependencies": {
"acorn": "^8.12.1",
- "acorn-jsx": "^5.3.2",
- "browserslist": "^4.23.1",
- "core-js": "^3.37.1"
+ "acorn-jsx": "^5.3.2"
+ },
+ "engines": {
+ "bun": "^1.1.27"
},
"optionalDependencies": {
"@types/react": "^18.3.3",
@@ -29130,29 +29468,6 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
- "node_modules/readable-stream/node_modules/buffer": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
- "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.2.1"
- }
- },
"node_modules/readable-web-to-node-stream": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz",
@@ -29297,9 +29612,9 @@
"integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A=="
},
"node_modules/regenerate-unicode-properties": {
- "version": "10.1.1",
- "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz",
- "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==",
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz",
+ "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==",
"dependencies": {
"regenerate": "^1.4.2"
},
@@ -29716,7 +30031,8 @@
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
- "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
+ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+ "dev": true
},
"node_modules/resize-observer-polyfill": {
"version": "1.5.1",
@@ -29881,9 +30197,9 @@
}
},
"node_modules/rimraf/node_modules/lru-cache": {
- "version": "11.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.0.tgz",
- "integrity": "sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==",
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.1.tgz",
+ "integrity": "sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==",
"engines": {
"node": "20 || >=22"
}
@@ -30043,11 +30359,11 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/sass": {
- "version": "1.77.8",
- "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.8.tgz",
- "integrity": "sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==",
+ "version": "1.79.1",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.79.1.tgz",
+ "integrity": "sha512-+mA7svoNKeL0DiJqZGeR/ZGUu8he4I8o3jyUcOFyo4eBJrwNgIMmAEwCMo/N2Y3wdjOBcRzoNxZIOtrtMX8EXg==",
"dependencies": {
- "chokidar": ">=3.0.0 <4.0.0",
+ "chokidar": "^4.0.0",
"immutable": "^4.0.0",
"source-map-js": ">=0.6.2 <2.0.0"
},
@@ -30097,6 +30413,32 @@
}
}
},
+ "node_modules/sass/node_modules/chokidar": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.0.tgz",
+ "integrity": "sha512-mxIojEAQcuEvT/lyXq+jf/3cO/KoA6z4CeNDGGevTybECPOMFCnQy3OPahluUkbqgPNGw5Bi78UC7Po6Lhy+NA==",
+ "dependencies": {
+ "readdirp": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/sass/node_modules/readdirp": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.1.tgz",
+ "integrity": "sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==",
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/sax": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
@@ -30231,9 +30573,9 @@
"integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow=="
},
"node_modules/send": {
- "version": "0.18.0",
- "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
- "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+ "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
"dependencies": {
"debug": "2.6.9",
"depd": "2.0.0",
@@ -30266,10 +30608,24 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
- "node_modules/send/node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ "node_modules/send/node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/send/node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
},
"node_modules/serialize-javascript": {
"version": "6.0.2",
@@ -30371,14 +30727,14 @@
}
},
"node_modules/serve-static": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
- "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "version": "1.16.2",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
+ "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
"dependencies": {
- "encodeurl": "~1.0.2",
+ "encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
- "send": "0.18.0"
+ "send": "0.19.0"
},
"engines": {
"node": ">= 0.8.0"
@@ -30667,6 +31023,14 @@
"node": ">=10"
}
},
+ "node_modules/simple-xml-to-json": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/simple-xml-to-json/-/simple-xml-to-json-1.2.3.tgz",
+ "integrity": "sha512-kWJDCr9EWtZ+/EYYM5MareWj2cRnZGF93YDNpH4jQiHB+hBIZnfPFSQiVMzZOdk+zXWqTZ/9fTeQNu2DqeiudA==",
+ "engines": {
+ "node": ">=20.12.2"
+ }
+ },
"node_modules/simplify-js": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/simplify-js/-/simplify-js-1.2.4.tgz",
@@ -30810,9 +31174,9 @@
}
},
"node_modules/source-map-js": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
- "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"engines": {
"node": ">=0.10.0"
}
@@ -31070,9 +31434,9 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/streamx": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.19.0.tgz",
- "integrity": "sha512-5z6CNR4gtkPbwlxyEqoDGDmWIzoNJqCBt4Eac1ICP9YaIT08ct712cFj0u1rx4F8luAuL+3Qc+RFIdI4OX00kg==",
+ "version": "2.20.1",
+ "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.20.1.tgz",
+ "integrity": "sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA==",
"dependencies": {
"fast-fifo": "^1.3.2",
"queue-tick": "^1.0.1",
@@ -31134,9 +31498,9 @@
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/string-width/node_modules/ansi-regex": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
- "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+ "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
"engines": {
"node": ">=12"
},
@@ -31337,15 +31701,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/strip-final-newline": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
- "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -31395,17 +31750,17 @@
}
},
"node_modules/style-to-object": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.6.tgz",
- "integrity": "sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA==",
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz",
+ "integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==",
"dependencies": {
- "inline-style-parser": "0.2.3"
+ "inline-style-parser": "0.2.4"
}
},
"node_modules/styled-components": {
- "version": "6.1.12",
- "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.12.tgz",
- "integrity": "sha512-n/O4PzRPhbYI0k1vKKayfti3C/IGcPf+DqcrOB7O/ab9x4u/zjqraneT5N45+sIe87cxrCApXM8Bna7NYxwoTA==",
+ "version": "6.1.13",
+ "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.13.tgz",
+ "integrity": "sha512-M0+N2xSnAtwcVAQeFEsGWFFxXDftHUD7XrKla06QbpUMmbmtFBMMTcKWvFXtWxuD5qQkB8iU5gk6QASlx2ZRMw==",
"dependencies": {
"@emotion/is-prop-valid": "1.2.2",
"@emotion/unitless": "0.8.1",
@@ -31602,9 +31957,9 @@
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/terser": {
- "version": "5.31.6",
- "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz",
- "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==",
+ "version": "5.33.0",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.33.0.tgz",
+ "integrity": "sha512-JuPVaB7s1gdFKPKTelwUyRq5Sid2A3Gko2S0PncwdBq7kN9Ti9HPWDQ06MPsEDGsZeVESjKEnyGy68quBk1w6g==",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
@@ -31709,9 +32064,9 @@
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
},
"node_modules/text-decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz",
- "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.0.tgz",
+ "integrity": "sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg==",
"dependencies": {
"b4a": "^1.6.4"
}
@@ -31748,11 +32103,6 @@
"integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
"dev": true
},
- "node_modules/timm": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz",
- "integrity": "sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw=="
- },
"node_modules/tiny-inflate": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
@@ -31768,11 +32118,32 @@
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
"integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="
},
+ "node_modules/tinyexec": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.0.tgz",
+ "integrity": "sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg=="
+ },
"node_modules/tinyqueue": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz",
"integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA=="
},
+ "node_modules/tldts": {
+ "version": "6.1.47",
+ "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.47.tgz",
+ "integrity": "sha512-R/K2tZ5MiY+mVrnSkNJkwqYT2vUv1lcT6wJvd2emGaMJ7PHUGRY4e3tUsdFCXgqxi2QgbHjL3yJgXCo40v9Hxw==",
+ "dependencies": {
+ "tldts-core": "^6.1.47"
+ },
+ "bin": {
+ "tldts": "bin/cli.js"
+ }
+ },
+ "node_modules/tldts-core": {
+ "version": "6.1.47",
+ "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.47.tgz",
+ "integrity": "sha512-6SWyFMnlst1fEt7GQVAAu16EGgFK0cLouH/2Mk6Ftlwhv3Ol40L0dlpGMcnnNiiOMyD2EV/aF3S+U2nKvvLvrA=="
+ },
"node_modules/to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@@ -31864,25 +32235,14 @@
}
},
"node_modules/tough-cookie": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
- "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz",
+ "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==",
"dependencies": {
- "psl": "^1.1.33",
- "punycode": "^2.1.1",
- "universalify": "^0.2.0",
- "url-parse": "^1.5.3"
+ "tldts": "^6.1.32"
},
"engines": {
- "node": ">=6"
- }
- },
- "node_modules/tough-cookie/node_modules/universalify": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
- "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
- "engines": {
- "node": ">= 4.0.0"
+ "node": ">=16"
}
},
"node_modules/tr46": {
@@ -31954,6 +32314,7 @@
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
"integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=16"
},
@@ -32539,9 +32900,9 @@
}
},
"node_modules/type-fest": {
- "version": "4.25.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.25.0.tgz",
- "integrity": "sha512-bRkIGlXsnGBRBQRAY56UXBm//9qH4bmJfFvq83gSz41N282df+fjy8ofcEgc1sM8geNt5cl6mC2g9Fht1cs8Aw==",
+ "version": "4.26.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.1.tgz",
+ "integrity": "sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==",
"engines": {
"node": ">=16"
},
@@ -32635,9 +32996,9 @@
}
},
"node_modules/typescript": {
- "version": "5.5.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
- "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
+ "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -32652,15 +33013,15 @@
"integrity": "sha512-7sI4e/bZijOzyURng88oOFZCISQPTHozfE2sUu5AviFYk5QV7fYGb6YiDl+vKjF/pICA354JImBImL9XJWUvdQ=="
},
"node_modules/typescript-eslint": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.3.0.tgz",
- "integrity": "sha512-EvWjwWLwwKDIJuBjk2I6UkV8KEQcwZ0VM10nR1rIunRDIP67QJTZAHBXTX0HW/oI1H10YESF8yWie8fRQxjvFA==",
+ "version": "8.6.0",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.6.0.tgz",
+ "integrity": "sha512-eEhhlxCEpCd4helh3AO1hk0UP2MvbRi9CtIAJTVPQjuSXOOO2jsEacNi4UdcJzZJbeuVg1gMhtZ8UYb+NFYPrA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/eslint-plugin": "8.3.0",
- "@typescript-eslint/parser": "8.3.0",
- "@typescript-eslint/utils": "8.3.0"
+ "@typescript-eslint/eslint-plugin": "8.6.0",
+ "@typescript-eslint/parser": "8.6.0",
+ "@typescript-eslint/utils": "8.6.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -32709,6 +33070,11 @@
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="
},
+ "node_modules/ufo": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz",
+ "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ=="
+ },
"node_modules/uid-safe": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
@@ -32751,9 +33117,9 @@
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
},
"node_modules/unicode-canonical-property-names-ecmascript": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
- "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz",
+ "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==",
"engines": {
"node": ">=4"
}
@@ -32771,9 +33137,9 @@
}
},
"node_modules/unicode-match-property-value-ecmascript": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz",
- "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz",
+ "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==",
"engines": {
"node": ">=4"
}
@@ -33056,6 +33422,7 @@
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+ "dev": true,
"dependencies": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"
@@ -33071,20 +33438,6 @@
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ=="
},
- "node_modules/url/node_modules/qs": {
- "version": "6.13.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
- "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
- "dependencies": {
- "side-channel": "^1.0.6"
- },
- "engines": {
- "node": ">=0.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/use-composed-ref": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz",
@@ -33577,9 +33930,9 @@
}
},
"node_modules/webpack-dev-middleware/node_modules/memfs": {
- "version": "4.11.1",
- "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.11.1.tgz",
- "integrity": "sha512-LZcMTBAgqUUKNXZagcZxvXXfgF1bHX7Y7nQ0QyEiNbRJgE29GhgPd8Yna1VQcLlPiHt/5RFJMWYN9Uv/VPNvjQ==",
+ "version": "4.11.2",
+ "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.11.2.tgz",
+ "integrity": "sha512-VcR7lEtgQgv7AxGkrNNeUAimFLT+Ov8uGu1LuOfbe/iF/dKoh/QgpoaMZlhfejvLtMxtXYyeoT7Ar1jEbWdbPA==",
"dependencies": {
"@jsonjoy.com/json-pack": "^1.0.3",
"@jsonjoy.com/util": "^1.3.0",
@@ -33595,9 +33948,9 @@
}
},
"node_modules/webpack-dev-server": {
- "version": "5.0.4",
- "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz",
- "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.1.0.tgz",
+ "integrity": "sha512-aQpaN81X6tXie1FoOB7xlMfCsN19pSvRAeYUHOdFWOlhpQ/LlbfTqYwwmEDFV0h8GGuqmCmKmT+pxcUV/Nt2gQ==",
"dev": true,
"dependencies": {
"@types/bonjour": "^3.5.13",
@@ -33613,8 +33966,7 @@
"colorette": "^2.0.10",
"compression": "^1.7.4",
"connect-history-api-fallback": "^2.0.0",
- "default-gateway": "^6.0.3",
- "express": "^4.17.3",
+ "express": "^4.19.2",
"graceful-fs": "^4.2.6",
"html-entities": "^2.4.0",
"http-proxy-middleware": "^2.0.3",
@@ -33622,14 +33974,13 @@
"launch-editor": "^2.6.1",
"open": "^10.0.3",
"p-retry": "^6.2.0",
- "rimraf": "^5.0.5",
"schema-utils": "^4.2.0",
"selfsigned": "^2.4.1",
"serve-index": "^1.9.1",
"sockjs": "^0.3.24",
"spdy": "^4.0.2",
- "webpack-dev-middleware": "^7.1.0",
- "ws": "^8.16.0"
+ "webpack-dev-middleware": "^7.4.2",
+ "ws": "^8.18.0"
},
"bin": {
"webpack-dev-server": "bin/webpack-dev-server.js"
@@ -33662,21 +34013,6 @@
"node": ">= 10"
}
},
- "node_modules/webpack-dev-server/node_modules/rimraf": {
- "version": "5.0.10",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
- "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==",
- "dev": true,
- "dependencies": {
- "glob": "^10.3.7"
- },
- "bin": {
- "rimraf": "dist/esm/bin.mjs"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
"node_modules/webpack-hot-middleware": {
"version": "2.26.1",
"resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.26.1.tgz",
@@ -33792,11 +34128,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/whatwg-fetch": {
- "version": "3.6.20",
- "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz",
- "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg=="
- },
"node_modules/whatwg-mimetype": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
@@ -34101,9 +34432,9 @@
}
},
"node_modules/wrap-ansi/node_modules/ansi-regex": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
- "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+ "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
"engines": {
"node": ">=12"
},
@@ -34162,17 +34493,6 @@
}
}
},
- "node_modules/xhr": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz",
- "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==",
- "dependencies": {
- "global": "~4.4.0",
- "is-function": "^1.0.1",
- "parse-headers": "^2.0.0",
- "xtend": "^4.0.0"
- }
- },
"node_modules/xml-lexer": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/xml-lexer/-/xml-lexer-0.2.2.tgz",
@@ -34273,6 +34593,7 @@
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "dev": true,
"engines": {
"node": ">=0.4"
}
@@ -34398,6 +34719,14 @@
"node": ">= 14"
}
},
+ "node_modules/zod": {
+ "version": "3.23.8",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
+ "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
"node_modules/zwitch": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
diff --git a/package.json b/package.json
index 51e7cf8a9..20fa219b3 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,7 @@
"tsc": "tsc -t es5"
},
"devDependencies": {
- "@eslint/js": "^9.9.1",
+ "@eslint/js": "^9.10.0",
"@types/adm-zip": "^0.5.5",
"@types/animejs": "^3.1.12",
"@types/archiver": "^6.0.2",
@@ -72,8 +72,8 @@
"@types/youtube": "^0.1.0",
"chai": "^5.0.0",
"cross-env": "^7.0.3",
- "eslint": "^9.9.1",
- "eslint-plugin-react": "^7.35.0",
+ "eslint": "^9.10.0",
+ "eslint-plugin-react": "^7.36.1",
"globals": "^15.9.0",
"jsdom": "^25.0.0",
"mocha": "^10.2.0",
@@ -83,7 +83,7 @@
"ts-loader": "^9.5.1",
"ts-node": "^10.9.1",
"ts-node-dev": "^2.0.0",
- "typescript-eslint": "^8.3.0",
+ "typescript-eslint": "^8.6.0",
"webpack-dev-server": "^5.0.4"
},
"dependencies": {
@@ -101,12 +101,13 @@
"@fortawesome/free-regular-svg-icons": "^6.5.1",
"@fortawesome/free-solid-svg-icons": "^6.5.1",
"@fortawesome/react-fontawesome": "^0.2.0",
- "@fullcalendar/core": "^6.1.10",
+ "@fullcalendar/core": "^6.1.15",
"@fullcalendar/daygrid": "^6.1.10",
"@fullcalendar/multimonth": "^6.1.10",
+ "@fullcalendar/timegrid": "^6.1.15",
"@internationalized/date": "^3.5.0",
- "@mui/icons-material": "^5.14.19",
- "@mui/material": "^5.14.19",
+ "@mui/icons-material": "^6.0.1",
+ "@mui/material": "^6.0.1",
"@octokit/core": "^6.0.1",
"@react-google-maps/api": "^2.19.2",
"@react-spring/web": "^9.7.3",
@@ -129,10 +130,11 @@
"@types/reveal": "^4.2.0",
"@types/supercluster": "^7.1.3",
"@types/textfit": "^2.4.4",
- "@types/web": "^0.0.157",
+ "@types/web": "^0.0.163",
"@types/webpack-hot-middleware": "^2.25.9",
"@webscopeio/react-textarea-autocomplete": "^4.9.2",
"adm-zip": "^0.5.10",
+ "any-base": "^1.1.0",
"archiver": "^7.0.1",
"async": "^3.2.5",
"axios": "^1.6.2",
@@ -147,7 +149,7 @@
"body-parser": "^1.20.2",
"bootstrap": "^5.3.2",
"brotli": "^1.3.3",
- "browndash-components": "^0.1.45",
+ "browndash-components": "^0.1.47",
"browser-assert": "^1.2.1",
"bson": "^6.2.0",
"canvas": "^2.11.2",
@@ -171,7 +173,7 @@
"D": "^1.0.0",
"d3": "^7.8.5",
"depcheck": "^1.4.7",
- "dotenv": "^16.3.1",
+ "dotenv": "^16.4.5",
"eslint-webpack-plugin": "^4.1.0",
"exif": "^0.6.0",
"exifr": "^7.1.3",
@@ -186,16 +188,17 @@
"file-saver": "^2.0.5",
"find-in-files": "^0.5.0",
"fit-curve": "^0.2.0",
- "flexlayout-react": "^0.7.15",
+ "flexlayout-react": "^0.8.0",
"fluent-ffmpeg": "^2.1.2",
"forever-agent": "^0.6.1",
"fork-ts-checker-webpack-plugin": "^9.0.2",
"form-data": "^4.0.0",
"formidable": "3.5.1",
+ "fullcalendar": "^6.1.15",
"function-plot": "^1.23.3",
"golden-layout": "^2.6.0",
"google-auth-library": "^9.4.1",
- "googleapis": "^142.0.0",
+ "googleapis": "^144.0.0",
"googlephotos": "^0.3.5",
"got": "^14.0.0",
"howler": "^2.2.4",
@@ -210,8 +213,9 @@
"image-data-uri": "^2.0.1",
"image-size": "^1.0.2",
"image-size-stream": "^1.1.0",
+ "install": "^0.13.0",
"is-plain-obj": "^4.1.0",
- "jimp": "^0.22.10",
+ "jimp": "^1.0.4",
"jpeg-autorotate": "^9.0.0",
"jquery": "^3.7.1",
"js-datepicker": "^5.18.2",
@@ -234,7 +238,7 @@
"node-stream-zip": "^1.15.0",
"nodemailer": "^6.9.7",
"nodemon": "^3.0.2",
- "npm": "^10.2.5",
+ "npm": "^10.8.1",
"openai": "^4.26.0",
"p-limit": "^6.1.0",
"passport": "^0.7.0",
@@ -268,6 +272,7 @@
"react-compound-slider": "^3.4.0",
"react-datepicker": "^7.3.0",
"react-dom": "^18.2.0",
+ "react-draggable": "^4.4.6",
"react-grid-layout": "^1.4.4",
"react-icons": "^5.0.1",
"react-jsx-parser": "^2.0.0",
@@ -305,7 +310,7 @@
"svgson": "^5.3.1",
"textarea-caret": "^3.1.0",
"textfit": "^2.4.0",
- "tough-cookie": "^4.1.3",
+ "tough-cookie": "^5.0.0",
"tslint": "^6.1.3",
"tslint-loader": "^3.5.4",
"typescript": "^5.3.3",
diff --git a/src/ClientUtils.ts b/src/ClientUtils.ts
index 55801df81..01eda7e98 100644
--- a/src/ClientUtils.ts
+++ b/src/ClientUtils.ts
@@ -648,20 +648,14 @@ export function DivWidth(ele: HTMLElement | null): number {
}
export function dateRangeStrToDates(dateStr: string) {
+ const toDate = (str: string) => {
+ return !str.includes('T') && str.includes('-') ? new Date(Number(str.split('-')[0]), Number(str.split('-')[1]) - 1, Number(str.split('-')[2])) : new Date(str);
+ };
// dateStr in yyyy-mm-dd format
const dateRangeParts = dateStr.split('|'); // splits into from and to date
- const fromParts = dateRangeParts[0].split('-');
- const toParts = dateRangeParts[1].split('-');
-
- const fromYear = parseInt(fromParts[0]);
- const fromMonth = parseInt(fromParts[1]) - 1;
- const fromDay = parseInt(fromParts[2]);
-
- const toYear = parseInt(toParts[0]);
- const toMonth = parseInt(toParts[1]) - 1;
- const toDay = parseInt(toParts[2]);
-
- return [new Date(fromYear, fromMonth, fromDay), new Date(toYear, toMonth, toDay)];
+ if (dateRangeParts.length < 2 && !dateRangeParts[0]) return { start: new Date(), end: new Date() };
+ if (dateRangeParts.length < 2) return { start: toDate(dateRangeParts[0]), end: toDate(dateRangeParts[0]) };
+ return { start: new Date(dateRangeParts[0]), end: new Date(dateRangeParts[1]) };
}
function replaceCanvases(oldDiv: HTMLElement, newDiv: HTMLElement) {
diff --git a/src/client/Network.ts b/src/client/Network.ts
index 204fcf0ac..9afdc844f 100644
--- a/src/client/Network.ts
+++ b/src/client/Network.ts
@@ -50,7 +50,7 @@ export namespace Networking {
if (!fileguidpairs.length) {
return [];
}
- const maxFileSize = 6000000;
+ const maxFileSize = 50000000;
if (fileguidpairs.some(f => f.file.size > maxFileSize)) {
return new Promise<Upload.FileResponse<T>[]>(res => res([{ source: { newFilename: '', mimetype: '' } as formidable.File, result: new Error(`max file size (${maxFileSize / 1000000}MB) exceeded`) }]));
}
diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts
index 20c810651..209e8e87e 100644
--- a/src/client/apis/gpt/GPT.ts
+++ b/src/client/apis/gpt/GPT.ts
@@ -1,4 +1,4 @@
-import { ChatCompletionMessageParam } from 'openai/resources';
+import { ChatCompletionMessageParam, Image } from 'openai/resources';
import { openai } from './setup';
enum GPTCallType {
@@ -14,6 +14,10 @@ enum GPTCallType {
DATA = 'data',
DRAW = 'draw',
COLOR = 'color',
+ RUBRIC = 'rubric',
+ TYPE = 'type',
+ SUBSET = 'subset',
+ INFO = 'info',
}
type GPTCallOpts = {
@@ -28,6 +32,7 @@ const callTypeMap: { [type: string]: GPTCallOpts } = {
summary: { model: 'gpt-4-turbo', maxTokens: 256, temp: 0.5, prompt: 'Summarize the text given in simpler terms.' },
edit: { model: 'gpt-4-turbo', maxTokens: 256, temp: 0.5, prompt: 'Reword the text.' },
flashcard: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'Make flashcards out of this text with each question and answer labeled. Do not label each flashcard and do not include asterisks: ' },
+
completion: { model: 'gpt-4-turbo', maxTokens: 256, temp: 0.5, prompt: "You are a helpful assistant. Answer the user's prompt." },
mermaid: {
model: 'gpt-4-turbo',
@@ -44,8 +49,8 @@ const callTypeMap: { [type: string]: GPTCallOpts } = {
sort: {
model: 'gpt-4o',
maxTokens: 2048,
- temp: 0.5,
- prompt: "I'm going to give you a list of descriptions. Each one is seperated by ====== on either side. They will vary in length, so make sure to only seperate when you see ======. Sort them into lists by shared content. MAKE SURE EACH DESCRIPTOR IS IN ONLY ONE LIST. Generate only the list with each list seperated by ====== with the elements seperated by ~~~~~~. Try to do around 4 groups, but a little more or less is ok.",
+ temp: 0.25,
+ prompt: "The user is going to give you a list of descriptions. Each one is separated by `======` on either side. Descriptions will vary in length, so make sure to only separate when you see `======`. Sort them by the user's specifications. Make sure each description is only in the list once. Each item should be separated by `======`. Immediately afterward, surrounded by `------` on BOTH SIDES, provide some insight into your reasoning for the way you sorted (and mention nothing about the formatting details given in this description). It is VERY important that you format it exactly as described, ensuring the proper number of `=` and `-` (6 of each) and NO commas",
},
describe: { model: 'gpt-4-vision-preview', maxTokens: 2048, temp: 0, prompt: 'Describe these images in 3-5 words' },
chatcard: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'Answer the following question as a short flashcard response. Do not include a label.' },
@@ -53,7 +58,35 @@ const callTypeMap: { [type: string]: GPTCallOpts } = {
model: 'gpt-4-turbo',
maxTokens: 1024,
temp: 0,
- prompt: 'List unique differences between the content of the UserAnswer and Rubric. Before each difference, label it and provide any additional information the UserAnswer missed and explain it in second person without separating it into UserAnswer and Rubric content and additional information. If there are no differences, say correct',
+ prompt: "BRIEFLY (<50 words) describe any differences between the rubric and the user's answer answer in second person. If there are no differences, say correct",
+ },
+
+ rubric: {
+ model: 'gpt-4-turbo',
+ maxTokens: 1024,
+ temp: 0,
+ prompt: "BRIEFLY (<25 words) provide a definition for the following term. It will be used as a rubric to evaluate the user's understanding of the topic",
+ },
+
+ type: {
+ model: 'gpt-4-turbo',
+ maxTokens: 1024,
+ temp: 0,
+ prompt: "I'm going to provide you with a question. Based on the question, is the user asking you to 1. Assigns docs with tags(like star / heart etc)/labels, 2. Filter docs, 3. Provide information about a specific doc 4. Provide a specific doc based on a question/information 5. Provide general information 6. Put cards in a specific order. Answer with only the number for 2-6. For number one, provide the number (1) and the appropriate tag",
+ },
+
+ subset: {
+ model: 'gpt-4-turbo',
+ maxTokens: 1024,
+ temp: 0,
+ prompt: "I'm going to give you a list of descriptions. Each one is separated by `======` on either side. Descriptions will vary in length, so make sure to only separate when you see `======`. Based on the question the user asks, provide a subset of the given descriptions that best matches the user's specifications. Make sure each description is only in the list once. Each item should be separated by `======`. Immediately afterward, surrounded by `------` on BOTH SIDES, provide some insight into your reasoning in the 2nd person (and mention nothing about the formatting details given in this description). It is VERY important that you format it exactly as described, ensuring the proper number of `=` and `-` (6 of each) and no commas",
+ },
+
+ info: {
+ model: 'gpt-4-turbo',
+ maxTokens: 1024,
+ temp: 0,
+ prompt: "Answer the user's question with a short (<100 word) response. If a particular document is selected I will provide that information (which may help with your response)",
},
draw: {
model: 'gpt-4o',
@@ -84,7 +117,7 @@ const gptAPICall = async (inputTextIn: string, callType: GPTCallType, prompt?: a
try {
lastCall = inputText;
- const usePrompt = prompt ? opts.prompt + prompt : opts.prompt;
+ const usePrompt = prompt ? prompt + opts.prompt : opts.prompt;
const messages: ChatCompletionMessageParam[] = [
{ role: 'system', content: usePrompt },
{ role: 'user', content: inputText },
@@ -110,7 +143,7 @@ const gptImageCall = async (prompt: string, n?: number) => {
n: n ?? 1,
size: '1024x1024',
});
- return response.data.map((data: any) => data.url);
+ return response.data.map((data: Image) => data.url);
// return response.data.data[0].url;
} catch (err) {
console.error(err);
diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts
index dcb5e1fe3..0699ea09f 100644
--- a/src/client/documents/DocUtils.ts
+++ b/src/client/documents/DocUtils.ts
@@ -243,7 +243,10 @@ export namespace DocUtils {
Object.keys(scripts).forEach(key => {
const script = scripts[key] as string;
if (ScriptCast(doc[key])?.script.originalScript !== scripts[key] && script) {
+ const additionalItems: { [key: string]: unknown } = {};
+ script.match(/_[a-zA-Z]*_/)?.forEach(match => (additionalItems[match] = 'any'));
(key.startsWith('_') ? doc : Doc.GetProto(doc))[key] = ScriptField.MakeScript(script, {
+ ...additionalItems,
this: Doc.name,
dragData: Doc.DocDragDataName,
value: 'any',
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index 5a5c3d5bf..59a121de7 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -40,7 +40,6 @@ export enum DocumentType {
COMPARISON = 'comparison',
PUSHPIN = 'pushpin',
MAPROUTE = 'maproute',
- CALENDAR = 'calendar',
SCRIPTDB = 'scriptdb', // database of scripts
GROUPDB = 'groupdb', // database of groups
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 91bba4755..ba1bc8b7a 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -260,6 +260,7 @@ export class DocumentOptions {
_layout_noSidebar?: BOOLt = new BoolInfo('whether to display the sidebar toggle button');
layout_boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow
layout_maxShown?: NUMt = new NumInfo('maximum number of children to display at one time (see multicolumnview)');
+ _layout_dontCenter?: STRt = new StrInfo("whether collections will center their content - values of 'x', 'xy', or 'y'");
_layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents');
_layout_autoHeightMargins?: NUMt = new NumInfo('Margin heights to be added to the computed auto height of a Doc');
_layout_curPage?: NUMt = new NumInfo('current page of a PDF or other? paginated document', false);
@@ -272,6 +273,7 @@ export class DocumentOptions {
_layout_showTitle?: string; // field name to display in header (:hover is an optional suffix)
_layout_showSidebar?: BOOLt = new BoolInfo('whether an annotationsidebar should be displayed for text docuemnts');
_layout_showCaption?: string; // which field to display in the caption area. leave empty to have no caption
+ _layout_showTags?: BOOLt = new BoolInfo('whether to show the list of document tags at the bottom of a DocView');
_chromeHidden?: BOOLt = new BoolInfo('whether the editing chrome for a document is hidden');
hideClickBehaviors?: BOOLt = new BoolInfo('whether to hide click behaviors in context menu');
@@ -450,6 +452,7 @@ export class DocumentOptions {
onDragStart?: ScriptField; // script to execute at start of drag operation -- e.g., when a "creator" button is dragged this script generates a different document to drop
target?: Doc; // available for use in scripts. used to provide a document parameter to the script (Note, this is a convenience entry since any field could be used for parameterizing a script)
tags?: LISTt = new ListInfo('hashtags added to document, typically using a text view', true);
+ tags_chat?: LISTt = new ListInfo('hashtags added to document by chatGPT', true);
treeView_HideTitle?: BOOLt = new BoolInfo('whether to hide the top document title of a tree view');
treeView_HideUnrendered?: BOOLt = new BoolInfo("tells tree view not to display documents that have an 'layout_unrendered' tag unless they also have a treeView_FieldKey tag (presBox)");
treeView_HideHeaderIfTemplate?: BOOLt = new BoolInfo('whether to hide the header for a document in a tree view only if a childLayoutTemplate is provided (presBox)');
@@ -485,8 +488,7 @@ export class DocumentOptions {
userColor?: STRt = new StrInfo('color associated with a Dash user (seen in header fields of shared documents)');
cardSort?: STRt = new StrInfo('way cards are sorted in deck view');
- cardSort_customField?: STRt = new StrInfo('field key used for sorting cards');
- cardSort_visibleSortGroups?: List<number>; // which sorting values are being filtered (shown)
+ cardSort_isDesc?: BOOLt = new BoolInfo('whether the cards are sorted ascending or descending');
}
export const DocOptions = new DocumentOptions();
@@ -912,7 +914,15 @@ export namespace Docs {
}
export function CalendarDocument(options: DocumentOptions, documents: Array<Doc>) {
- return InstanceFromProto(Prototypes.get(DocumentType.CALENDAR), new List(documents), { ...options });
+ const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), {
+ _layout_nativeDimEditable: true,
+ _layout_reflowHorizontal: true,
+ _layout_reflowVertical: true,
+ ...options,
+ _type_collection: CollectionViewType.Calendar,
+ });
+ documents.forEach(d => Doc.SetContainer(d, inst));
+ return inst;
}
// shouldn't ever need to create a KVP document-- instead set the LayoutTemplateString to be a KeyValueBox for the DocumentView (see addDocTab in TabDocView)
@@ -969,12 +979,8 @@ export namespace Docs {
return doc;
}
- export function CalendarCollectionDocument(documents: Array<Doc>, options: DocumentOptions) {
- return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _type_collection: CollectionViewType.Calendar });
- }
-
export function StackingDocument(documents: Array<Doc>, options: DocumentOptions, id?: string, protoId?: string) {
- return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _type_collection: CollectionViewType.Stacking }, id, undefined, protoId);
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _layout_dontCenter: 'y', ...options, _type_collection: CollectionViewType.Stacking }, id, undefined, protoId);
}
export function NoteTakingDocument(documents: Array<Doc>, options: DocumentOptions, id?: string, protoId?: string) {
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 710f3e00a..f296d26bd 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -2,7 +2,7 @@
import { reaction, runInAction } from "mobx";
import * as rp from 'request-promise';
import { ClientUtils, OmitKeys } from "../../ClientUtils";
-import { Doc, DocListCast, DocListCastAsync, FieldType, Opt } from "../../fields/Doc";
+import { Doc, DocListCast, DocListCastAsync, FieldType, Opt, StrListCast } from "../../fields/Doc";
import { DocData } from "../../fields/DocSymbols";
import { InkTool } from "../../fields/InkField";
import { List } from "../../fields/List";
@@ -40,11 +40,12 @@ import { ColorScheme } from "./SettingsManager";
import { SnappingManager } from "./SnappingManager";
import { UndoManager } from "./UndoManager";
-interface Button {
+export interface Button {
// DocumentOptions fields a button can set
title?: string;
toolTip?: string;
icon?: string;
+ isSystem?: boolean;
btnType?: ButtonType;
numBtnMin?: number;
numBtnMax?: number;
@@ -388,7 +389,7 @@ pie title Minerals in my tap water
{key: "Chat", creator: Docs.Create.ChatDocument, opts: { _width: 300, _height: 300, }},
{key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 120, _header_pointerEvents: "all", _header_height: 50, _header_fontSize: 9,_layout_autoHeightMargins: 50, _layout_autoHeight: true, treeView_HideUnrendered: true}},
{key: "ViewSlide", creator: slideView, opts: { _width: 400, _height: 300, _xMargin: 3, _yMargin: 3,}},
- {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, dropAction: dropActionType.embed, treeView_HideTitle: true, _layout_fitWidth:true, layout_boxShadow: "0 0" }},
+ {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, _layout_dontCenter:'xy', dropAction: dropActionType.embed, treeView_HideTitle: true, _layout_fitWidth:true, layout_boxShadow: "0 0" }},
{key: "Tab", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }},
{key: "Slide", creator: opts => Docs.Create.TreeDocument([], opts), opts: { _width: 300, _height: 200, _type_collection: CollectionViewType.Tree,
treeView_HasOverlay: true, _text_fontSize: "20px", _layout_autoHeight: true,
@@ -497,6 +498,7 @@ pie title Minerals in my tap water
const reqdStackOpts:DocumentOptions ={
title: "menuItemPanel", childDragAction: dropActionType.same, layout_boxShadow: "rgba(0,0,0,0)", dontRegisterView: true, ignoreClick: true,
+ _layout_dontCenter: 'y',
_chromeHidden: true, _gridGap: 0, _yMargin: 0, _xMargin: 0, _layout_autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, isSystem: true,
};
return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdStackOpts, menuBtns, { dropConverter: "convertToButtons(dragData)" });
@@ -530,7 +532,7 @@ pie title Minerals in my tap water
// doc.myUserBtns = new PrefetchProxy(userBtns);
const reqdToolOps:DocumentOptions = {
title: "My Tools", isSystem: true, ignoreClick: true, layout_boxShadow: "0 0",
- layout_explainer: "This is a palette of documents that can be created.",
+ layout_explainer: "This is a palette of documents that can be created.", _layout_dontCenter: "y",
_layout_showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _dragOnlyWithinContainer: true, layout_hideContextMenu: true, _chromeHidden: true,
};
return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdToolOps, [creatorBtns, userBtns]);
@@ -683,37 +685,38 @@ pie title Minerals in my tap water
}
static stackTools(): Button[] {
return [
- { title: "Center", icon: "align-center", toolTip: "Center Align Stack", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"center", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+ { title: "V. Align", icon: "pallet", toolTip: "Center Align Stack", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"vcenter", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+ { title: "Center", icon: "align-center", toolTip: "Center Align Stack", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"hcenter", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
]
}
static cardTools(): Button[] {
return [
- { title: "Time", icon:"hourglass-half", toolTip:"Sort by most recent document creation", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"time", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
- { title: "Type", icon:"eye", toolTip:"Sort by document type", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"docType",funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
- { title: "Color", icon:"palette", toolTip:"Sort by document color", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"color", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
+ { title: "Time", icon:"hourglass-half", toolTip:"Sort by most recent document creation", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"time", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
+ { title: "Type", icon:"eye", toolTip:"Sort by document type", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"docType", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
+ { title: "Color", icon:"palette", toolTip:"Sort by document color", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"color", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
+ { title: "Tags", icon:"bolt", toolTip:"Sort by document's tags", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"tag", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
+ { title: "Pile", icon:"layer-group", toolTip:"View the cards as a pile in the free form view!",btnType: ButtonType.ClickButton, expertMode: false, toolType:"pile", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
+ { title: "Chat Popup",icon:"lightbulb", toolTip:"Toggle the chat popup's visibility!", width: 45, btnType: ButtonType.ToggleButton, expertMode: false, toolType:"toggle-chat",funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} },
+
+ { title: "Sort", icon: "sort" , toolTip: "Manage sort order / lock status", btnType: ButtonType.MultiToggleButton, toolType:"alignment", ignoreClick: true,
+ subMenu: [
+ { title: "Ascending", toolTip: "Sort the cards in ascending order", btnType: ButtonType.ToggleButton, icon: "sort-up", toolType:"up", ignoreClick: true, scripts: {onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} },
+ { title: "Descending",toolTip: "Sort the cards in descending order",btnType: ButtonType.ToggleButton, icon: "sort-down",toolType:"down",ignoreClick: true, scripts: {onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} },
+ ]},
]
}
- static labelTools(): Button[] {
- return [
- { title: "AI", icon:"robot", toolTip:"Add AI labels", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"chat", funcs: {hidden:`showFreeform ("chat", true)`},scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
- { title: "AIs", icon:"AI Sort", toolTip:"Filter AI labels", subMenu: this.cardGroupTools("chat"), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden:`!showFreeform("chat", true)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} },
- { title: "Like", icon:"heart", toolTip:"Add Like labels", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"like", funcs: {hidden:`showFreeform ("like", true)`},scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
- { title: "Likes", icon:"Likes", toolTip:"Filter likes", width: 10, subMenu: this.cardGroupTools("heart"), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden:`!showFreeform("like", true)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} },
- { title: "Star", icon:"star", toolTip:"Add Star labels", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"star", funcs: {hidden:`showFreeform ("star", true)`},scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
- { title: "Stars", icon:"Stars", toolTip:"Filter stars", width: 80, subMenu: this.cardGroupTools("star"), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden:`!showFreeform("star", true)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} },
- { title: "Idea", icon:"satellite", toolTip:"Add Idea labels", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"idea", funcs: {hidden:`showFreeform ("idea", true)`},scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
- { title: "Ideas", icon:"Ideas", toolTip:"Filter ideas", width: 80, subMenu: this.cardGroupTools("satellite"), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden:`!showFreeform("idea", true)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} },
- ]
- }
- static cardGroupTools(icon: string): Button[] {
+
+ static tagGroupTools(): Button[] {
+ const defaultTagButtonDescs = [
+ { title: "Star", isSystem: false,icon: "star", toolTip:"Click to toggle visibility of Star tagged Docs", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"#star", funcs: {}, scripts: { onClick: '{ return setTagFilter(this.toolType, _added_, _readOnly_);}'}},
+ { title: "Like", isSystem: false,icon: "heart", toolTip:"Click to toggle visibility of Like tagged Docs", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"#like", funcs: {}, scripts: { onClick: '{ return setTagFilter(this.toolType, _added_, _readOnly_);}'}},
+ { title: "Todo", isSystem: false,icon: "bolt", toolTip:"Click to toggle visibility of Todo tagged Docs", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"#todo", funcs: {}, scripts: { onClick: '{ return setTagFilter(this.toolType, _added_, _readOnly_);}'}},
+ { title: "Idea", isSystem: false,icon: "cloud", toolTip:"Click to toggle visibility of Idea tagged Docs", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"#idea", funcs: {}, scripts: { onClick: '{ return setTagFilter(this.toolType, _added_, _readOnly_);}'}},
+ ];
+ // hack: if there's no dashboard, create default filters. otherwise, just make sure that the Options button is preserved
return [
- { title: "1", icon, toolTip:"Click to toggle visibility", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"1", funcs: {hidden:`!cardHasLabel(this.toolType)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
- { title: "2", icon, toolTip:"Click to toggle visibility", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"2", funcs: {hidden:`!cardHasLabel(this.toolType)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
- { title: "3", icon, toolTip:"Click to toggle visibility", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"3", funcs: {hidden:`!cardHasLabel(this.toolType)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
- { title: "4", icon, toolTip:"Click to toggle visibility", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"4", funcs: {hidden:`!cardHasLabel(this.toolType)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
- { title: "5", icon, toolTip:"Click to toggle visibility", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"5", funcs: {hidden:`!cardHasLabel(this.toolType)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
- { title: "6", icon, toolTip:"Click to toggle visibility", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"6", funcs: {hidden:`!cardHasLabel(this.toolType)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
- { title: "7", icon, toolTip:"Click to toggle visibility", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"7", funcs: {hidden:`!cardHasLabel(this.toolType)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
+ { title:"Options",isSystem: true,icon: "gear", toolTip:"Click to customize list of filter buttons", btnType: ButtonType.ClickButton, expertMode: false, toolType:"-opts-",funcs: {}, scripts: { onClick: '{ return setTagFilter(this.toolType, false,_readOnly_);}'}},
+ ...(Doc.UserDoc().activeDashboard ? [] : defaultTagButtonDescs)
]
}
static viewTools(): Button[] {
@@ -732,8 +735,8 @@ pie title Minerals in my tap water
{ title: "Font", toolTip: "Font", width: 100, btnType: ButtonType.DropdownList, toolType:"font", ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'},
btnList: new List<string>(["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia", "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"]) },
{ title: "Font Size",toolTip: "Font size (%size)", btnType: ButtonType.NumberDropdownButton, toolType:"fontSize", ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 6 },
- { title: "Color", toolTip: "Font color (%color)", btnType: ButtonType.ColorButton, icon: "font", toolType:"fontColor",ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'}},
- { title: "Highlight",toolTip: "Font highlight", btnType: ButtonType.ColorButton, icon: "highlighter", toolType:"highlight",ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'}},
+ { title: "Color", toolTip: "Font color (%color)", btnType: ButtonType.ColorButton, icon: "font", toolType:"fontColor",ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'} },
+ { title: "Highlight",toolTip: "Font highlight", btnType: ButtonType.ColorButton, icon: "highlighter", toolType:"highlight",ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'} },
{ title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", toolType:"bold", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
{ title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", toolType:"italics", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
{ title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", toolType:"underline",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
@@ -742,12 +745,12 @@ pie title Minerals in my tap water
{ title: "Vcenter", toolTip: "Vertical center", btnType: ButtonType.ToggleButton, icon: "pallet", toolType:"vcent", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
{ title: "Align", toolTip: "Alignment", btnType: ButtonType.MultiToggleButton, toolType:"alignment", ignoreClick: true,
subMenu: [
- { title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}' }},
+ { title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
{ title: "Center", toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
{ title: "Right", toolTip: "Right align (Cmd-])", btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
]},
- { title: "Elide", toolTip: "Elide selection", btnType: ButtonType.ToggleButton, icon: "eye", toolType:"elide", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'}},
- { title: "Dictate", toolTip: "Dictate", btnType: ButtonType.ToggleButton, icon: "microphone", toolType:"dictation", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'}},
+ { title: "Elide", toolTip: "Elide selection", btnType: ButtonType.ToggleButton, icon: "eye", toolType:"elide", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
+ { title: "Dictate", toolTip: "Dictate", btnType: ButtonType.ToggleButton, icon: "microphone", toolType:"dictation", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
{ title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", toolType:"noAutoLink", expertMode:true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'}, funcs: {hidden: 'IsNoviceMode()'}},
// { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", scripts: {onClick:: 'toggleStrikethrough()'}},
// { title: "Superscript", tooltip: "Superscript", btnType: ButtonType.ToggleButton, icon: "superscript", scripts: {onClick:: 'toggleSuperscript()'}},
@@ -799,8 +802,8 @@ pie title Minerals in my tap water
}
static imageTools() {
return [
- { title: "Pixels",toolTip: "Set Native Pixel Sizze", btnType: ButtonType.ClickButton, icon: "portrait", scripts: { onClick: 'imageSetPixelSize();' }},
- { title: "Rotate",toolTip: "Rotate 90", btnType: ButtonType.ClickButton, icon: "redo-alt", scripts: { onClick: 'imageRotate90();' }},
+ { title: "Pixels",toolTip: "Set Native Pixel Size", btnType: ButtonType.ClickButton, icon: "portrait", scripts: { onClick: 'imageSetPixelSize();' }},
+ { title: "Rotate",toolTip: "Rotate 90", btnType: ButtonType.ClickButton, icon: "redo-alt", scripts: { onClick: 'imageRotate90();' }},
];
}
static contextMenuTools():Button[] {
@@ -809,7 +812,7 @@ pie title Minerals in my tap water
CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.Multicolumn,
CollectionViewType.Multirow, CollectionViewType.Time, CollectionViewType.Carousel,
CollectionViewType.Carousel3D, CollectionViewType.Card, CollectionViewType.Linear, CollectionViewType.Map,
- CollectionViewType.Grid, CollectionViewType.NoteTaking, ]),
+ CollectionViewType.Calendar, CollectionViewType.Grid, CollectionViewType.NoteTaking, ]),
title: "Perspective", toolTip: "View", btnType: ButtonType.DropdownList, ignoreClick: true, width: 100, scripts: { script: '{ return setView(value, _readOnly_); }'}},
{ title: "Pin", icon: "map-pin", toolTip: "Pin View to Trail", btnType: ButtonType.ClickButton, expertMode: false, width: 30, scripts: { onClick: 'pinWithView(altKey)'}, funcs: {hidden: "IsNoneSelected()"}},
{ title: "Header", icon: "heading", toolTip: "Doc Titlebar Color", btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'} },
@@ -819,25 +822,29 @@ pie title Minerals in my tap water
{ title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, width: 30, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}},
{ title: "Num", icon:"", toolTip: "Frame # (click to toggle edit mode)",btnType: ButtonType.TextButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}},
{ title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, width: 30, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}},
- { title: "Text", icon: "Text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), expertMode: false, toolType:DocumentType.RTF, funcs: { linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
- { title: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), expertMode: false, toolType:DocumentType.INK, funcs: {hidden: `IsExploreMode()`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
- { title: "Doc", icon: "Doc", toolTip: "Freeform Doc tools", subMenu: CurrentUserUtils.freeTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode, true)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
- { title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
- { title: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: CurrentUserUtils.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
- { title: "Card", icon: "Sort", toolTip: "Card sort", subMenu: CurrentUserUtils.cardTools(), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
- { title: "Label", icon: "Label", toolTip: "Assign card labels", subMenu: CurrentUserUtils.labelTools(), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
- { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected
- { title: "Video", icon: "Video", toolTip: "Video functions", subMenu: CurrentUserUtils.videoTools(), expertMode: false, toolType:DocumentType.VID, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when video is selected
- { title: "Image", icon: "Image", toolTip: "Image functions", subMenu: CurrentUserUtils.imageTools(), expertMode: false, toolType:DocumentType.IMG, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when image is selected
- { title: "Schema", icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(),expertMode: false,toolType:CollectionViewType.Schema,funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when Schema is selected
- ];
+
+ { title: "Text", icon: "Text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), expertMode: false, toolType:DocumentType.RTF, funcs: { linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
+ { title: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), expertMode: false, toolType:DocumentType.INK, funcs: {hidden: `IsExploreMode()`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
+ { title: "Doc", icon: "Doc", toolTip: "Freeform Doc tools", subMenu: CurrentUserUtils.freeTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode, true)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
+ { title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
+ { title: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: CurrentUserUtils.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
+
+ { title: "Card", icon: "Card", toolTip: "Card View Tools", subMenu: CurrentUserUtils.cardTools(), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
+ // { title: "Create", icon: "Create", toolTip: "Assign card labels", subMenu: CurrentUserUtils.labelTools(), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
+ { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected
+ { title: "Video", icon: "Video", toolTip: "Video functions", subMenu: CurrentUserUtils.videoTools(), expertMode: false, toolType:DocumentType.VID, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when video is selected
+ { title: "Image", icon: "Image", toolTip: "Image functions", subMenu: CurrentUserUtils.imageTools(), expertMode: false, toolType:DocumentType.IMG, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when image is selected
+ { title: "Schema", icon: "Schema", toolTip: "Schema functions", subMenu: CurrentUserUtils.schemaTools(), expertMode: false, toolType:CollectionViewType.Schema, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`}, linearBtnWidth:58 }, // Only when Schema is selected
+ { title: "Filter", icon: "=", toolTip: "Filter cards by tags", subMenu: CurrentUserUtils.tagGroupTools(),ignoreClick:true, toolType:DocumentType.COL, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, btnType: ButtonType.MultiToggleButton, width: 150},
+ ];
}
/// initializes a context menu button for the top bar context menu
static setupContextMenuButton(params:Button, btnDoc?:Doc, btnContainer?:Doc) {
const reqdOpts:DocumentOptions = {
- ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit as {[key:string]: string|undefined},
- color: Colors.WHITE, isSystem: true,
+ isSystem: true,
+ ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit,
+ color: Colors.WHITE,
_nativeWidth: params.width ?? 30, _width: params.width ?? 30,
_height: 30, _nativeHeight: 30, linearBtnWidth: params.linearBtnWidth,
toolType: params.toolType, expertMode: params.expertMode,
@@ -1006,6 +1013,7 @@ pie title Minerals in my tap water
doc.filterDocCount = 0;
doc.treeView_FreezeChildren = "remove|add";
doc.activePage = doc.activeDashboard === undefined ? 'home': doc.activePage;
+
this.setupLinkDocs(doc, linkDatabaseId);
this.setupSharedDocs(doc, sharingDocumentId); // sets up the right sidebar collection for mobile upload documents and sharing
this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon
@@ -1141,4 +1149,4 @@ ScriptingGlobals.add(function importDocument() { return CurrentUserUtils.import
// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function setInkToolDefaults() { Doc.ActiveTool = InkTool.None; });
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function getSharingDoc() { return Doc.SharingDoc() });
+ScriptingGlobals.add(function getSharingDoc() { return Doc.SharingDoc() }); \ No newline at end of file
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 83b83240e..5ae292760 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -269,8 +269,8 @@ export class DocumentManager {
if (options.openLocation?.includes(OpenWhere.lightbox)) {
// even if we found the document view, if the target is a lightbox, we try to open it in the lightbox to preserve lightbox semantics (eg, there's only one active doc in the lightbox)
const target = DocCast(targetDoc.annotationOn, targetDoc);
- const contextView = this.getDocumentView(DocCast(target.embedContainer));
- if (contextView?.ComponentView?.addDocTab?.(target, options.openLocation)) {
+ const compView = this.getDocumentView(DocCast(target.embedContainer))?.ComponentView;
+ if ((compView?.addDocTab ?? compView?._props.addDocTab)?.(target, options.openLocation)) {
await new Promise<void>(waitres => {
setTimeout(() => waitres());
});
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 7db13689d..81ea840f1 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -29,7 +29,7 @@ import { dropActionType } from './DropActionTypes';
import { SnappingManager } from './SnappingManager';
import { UndoManager } from './UndoManager';
-// eslint-disable-next-line @typescript-eslint/no-var-requires
+// eslint-disable-next-line @typescript-eslint/no-require-imports
const { contextMenuZindex } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore
/**
@@ -101,7 +101,6 @@ export namespace DragManager {
// event called when the drag operation results in a drop action
export class DropEvent {
- // eslint-disable-next-line no-useless-constructor
constructor(
readonly x: number,
readonly y: number,
@@ -569,7 +568,7 @@ export namespace DragManager {
AbortDrag();
await finishDrag?.(new DragCompleteEvent(true, docDragData));
DragManager.StartWindowDrag?.(e, docDragData.droppedDocuments, aborted => {
- if (!aborted && (docDragData?.dropAction === 'move' || docDragData?.dropAction === 'same')) {
+ if (!aborted && (docDragData?.dropAction === dropActionType.move || docDragData?.dropAction === dropActionType.same)) {
docDragData.removeDocument?.(docDragData?.draggedDocuments[0]);
}
});
diff --git a/src/typings/type_decls.d b/src/client/util/node_modules/type_decls.d
index 1a93bbe59..1a93bbe59 100644
--- a/src/typings/type_decls.d
+++ b/src/client/util/node_modules/type_decls.d
diff --git a/src/client/util/request-image-size.ts b/src/client/util/request-image-size.ts
index 7a2ecd486..c619192ed 100644
--- a/src/client/util/request-image-size.ts
+++ b/src/client/util/request-image-size.ts
@@ -35,7 +35,11 @@ module.exports = function requestImageSize(url: string) {
res.on('data', chunk => {
buffer = Buffer.concat([buffer, chunk]);
+ });
+
+ res.on('error', reject);
+ res.on('end', () => {
try {
size = imageSize(buffer);
if (size) {
@@ -46,11 +50,6 @@ module.exports = function requestImageSize(url: string) {
/* empty */
console.log('Error: ', err);
}
- });
-
- res.on('error', reject);
-
- res.on('end', () => {
if (!size) {
reject(new Error('Image has no size'));
return;
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 33e905a54..eced64524 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -465,7 +465,7 @@ export class DashboardView extends ObservableReactComponent<object> {
isSystem: true,
layout_explainer: 'All of the calendars that you have created will appear here.',
};
- const myCalendars = DocUtils.AssignScripts(Docs.Create.CalendarCollectionDocument([], reqdOpts));
+ const myCalendars = DocUtils.AssignScripts(Docs.Create.StackingDocument([], reqdOpts));
// { treeView_ChildDoubleClick: 'openPresentation(documentView.rootDoc)' }
return new PrefetchProxy(myCalendars);
}
diff --git a/src/client/views/DocumentButtonBar.scss b/src/client/views/DocumentButtonBar.scss
index 11614d627..ede277aae 100644
--- a/src/client/views/DocumentButtonBar.scss
+++ b/src/client/views/DocumentButtonBar.scss
@@ -29,6 +29,11 @@ $linkGap: 3px;
background: black;
height: 20px;
align-items: center;
+
+ .tags {
+ width: 40px;
+
+ }
}
.documentButtonBar-followTypes {
width: 20px;
@@ -153,6 +158,10 @@ $linkGap: 3px;
&:hover {
background-color: $black;
+
+ .documentButtonBar-pinTypes {
+ display: flex;
+ }
}
}
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 04c1d359c..28424c711 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -9,7 +9,7 @@ import * as React from 'react';
import { FaEdit } from 'react-icons/fa';
import { returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick } from '../../ClientUtils';
import { emptyFunction } from '../../Utils';
-import { Doc } from '../../fields/Doc';
+import { Doc, DocListCast } from '../../fields/Doc';
import { Cast, DocCast } from '../../fields/Types';
import { DocUtils, IsFollowLinkScript } from '../documents/DocUtils';
import { CalendarManager } from '../util/CalendarManager';
@@ -280,14 +280,38 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (
);
}
+ /**
+ * Allows for both the keywords and the icon tags to be shown using a quasi- multitoggle
+ */
@computed
get keywordButton() {
- return !DocumentView.Selected().length ? null : (
- <Tooltip title={<div className="dash-keyword-button">Open keyword menu</div>}>
- <div className="documentButtonBar-icon" style={{ color: 'white' }} onClick={() => DocumentView.Selected().map(dv => (dv.dataDoc.showTags = !dv.dataDoc.showTags))}>
- <FontAwesomeIcon className="documentdecorations-icon" icon="tag" />
- </div>
- </Tooltip>
+ const targetDoc = this.view0?.Document;
+
+ return !targetDoc ? null : (
+ <div className="documentButtonBar-icon">
+ {/* <div className="documentButtonBar-pinTypes" style={{ width: '40px' }}>
+ {metaBtn('tags', 'star')}
+ {metaBtn('keywords', 'id-card')}
+ </div> */}
+
+ <Tooltip title={<div className="dash-keyword-button">Open keyword menu</div>}>
+ <div
+ className="documentButtonBar-icon"
+ style={{ color: 'white' }}
+ onClick={undoable(e => {
+ const showing = DocumentView.Selected().some(dv => dv.showTags);
+ DocumentView.Selected().forEach(dv => {
+ dv.layoutDoc._layout_showTags = !showing;
+ if (e.shiftKey)
+ DocListCast(dv.Document[Doc.LayoutFieldKey(dv.Document) + '_annotations']).forEach(doc => {
+ if (doc.face) doc.hidden = showing;
+ });
+ });
+ }, 'show Doc tags')}>
+ <FontAwesomeIcon className="documentdecorations-icon" icon="tag" />
+ </div>
+ </Tooltip>
+ </div>
);
}
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 67e1054c3..346df10d5 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -38,6 +38,13 @@ $resizeHandler: 8px;
background: green;
border-radius: 50%;
}
+ .documentDecorations-tagsView {
+ position: absolute;
+ height: 100%;
+ pointer-events: all;
+ border-radius: 50%;
+ color: black;
+ }
}
.documentDecorations-container {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 8552003eb..7f6cfbb87 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -35,6 +35,7 @@ import { DocumentView } from './nodes/DocumentView';
import { ImageBox } from './nodes/ImageBox';
import { OpenWhere, OpenWhereMod } from './nodes/OpenWhere';
import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
+import { TagsView } from './TagsView';
interface DocumentDecorationsProps {
PanelWidth: number;
@@ -172,7 +173,8 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
!this._editingTitle && (this._accumulatedTitle = this._titleControlString.startsWith('$') ? (selected && Field.toKeyValueString(selected, this._titleControlString.substring(1))) || '-unset-' : this._titleControlString);
this._editingTitle = true;
this._keyinput.current && setTimeout(this._keyinput.current.focus);
- })
+ }),
+ false // can't preventDefault since that will mess up goldenlayout if you drag over the tab bar. so just stop propagation below.
);
e.stopPropagation();
}
@@ -194,7 +196,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
if (containers.size > 1) return false;
const { left, top } = dragDocView.getBounds || { left: 0, top: 0 };
const dragData = new DragManager.DocumentDragData(DocumentView.SelectedDocs(), dragDocView._props.dropAction);
- dragData.offset = dragDocView.screenToContentsTransform().transformDirection(e.x - left, e.y - top);
+ dragData.offset = dragDocView.screenToViewTransform().transformDirection(e.x - left, e.y - top);
dragData.moveDocument = dragDocView._props.moveDocument;
dragData.removeDocument = dragDocView._props.removeDocument;
dragData.isDocDecorationMove = true;
@@ -236,7 +238,8 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
if (dragFactory && DocCast(dragFactory.cloneOf).savedAsAnno) {
DocCast(dragFactory.cloneOf).savedAsAnno = undefined;
}
- iconView._props.removeDocument?.(iconView.Document);
+ if (iconView.Document.annotationOn && iconView.Document.face) iconView.Document.hidden = true;
+ else iconView._props.removeDocument?.(iconView.Document);
}
});
views.forEach(DocumentView.DeselectView);
@@ -342,7 +345,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
setRotateCenter = (seldocview: DocumentView, rotCenter: number[]) => {
const selDoc = seldocview.Document;
- const newloccentern = seldocview.screenToContentsTransform().transformPoint(rotCenter[0], rotCenter[1]);
+ const newloccentern = seldocview.screenToViewTransform().transformPoint(rotCenter[0], rotCenter[1]);
const newlocenter = [newloccentern[0] - NumCast(seldocview.layoutDoc._width) / 2, newloccentern[1] - NumCast(seldocview.layoutDoc._height) / 2];
const final = Utils.rotPt(newlocenter[0], newlocenter[1], -(NumCast(seldocview.Document._rotation) / 180) * Math.PI);
selDoc._rotation_centerX = final.x / NumCast(seldocview.layoutDoc._width);
@@ -637,7 +640,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
@computed get rotCenter() {
const lastView = DocumentView.Selected().lastElement();
if (lastView) {
- const invXf = lastView.screenToContentsTransform().inverse();
+ const invXf = lastView.screenToViewTransform().inverse();
const seldoc = lastView.layoutDoc;
const loccenter = Utils.rotPt(NumCast(seldoc._rotation_centerX) * NumCast(seldoc._width), NumCast(seldoc._rotation_centerY) * NumCast(seldoc._height), invXf.Rotate);
return invXf.transformPoint(loccenter.x + NumCast(seldoc._width) / 2, loccenter.y + NumCast(seldoc._height) / 2);
@@ -648,7 +651,6 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
render() {
const { b, r, x, y } = this.Bounds;
const seldocview = DocumentView.Selected().lastElement();
- const doc = DocumentView.SelectedDocs().lastElement();
if (SnappingManager.IsDragging || r - x < 1 || x === Number.MAX_VALUE || !seldocview || this._hidden || isNaN(r) || isNaN(b) || isNaN(x) || isNaN(y)) {
setTimeout(
action(() => {
@@ -840,12 +842,20 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
<div
className="link-button-container"
style={{
- top: `${doc[DocData].showTags ? 4 + seldocview.TagPanelHeight : 4}px`,
+ top: DocumentView.Selected().length > 1 ? 0 : `${seldocview.showTags ? 4 + seldocview.TagPanelHeight : 4}px`,
transform: `translate(${-this._resizeBorderWidth / 2 + 10}px, ${this._resizeBorderWidth + bounds.b - bounds.y + this._titleHeight}px) `,
}}>
<DocumentButtonBar views={() => DocumentView.Selected()} />
</div>
)}
+ <div
+ className="documentDecorations-tagsView"
+ style={{
+ top: `${seldocview.showTags ? 4 + seldocview.TagPanelHeight : 4}px`,
+ transform: `translate(${-this._resizeBorderWidth / 2 + 10}px, ${this._resizeBorderWidth + bounds.b - bounds.y + this._titleHeight}px) `,
+ }}>
+ {DocumentView.Selected().length > 1 ? <TagsView Views={DocumentView.Selected()} /> : null}
+ </div>
</div>
{useRotation && (
diff --git a/src/client/views/FilterPanel.scss b/src/client/views/FilterPanel.scss
index d6d2956aa..508b1ee1f 100644
--- a/src/client/views/FilterPanel.scss
+++ b/src/client/views/FilterPanel.scss
@@ -1,3 +1,4 @@
+
.filterBox-flyout {
display: block;
text-align: left;
@@ -228,6 +229,97 @@
vertical-align: middle;
}
+.filterHotKey-button {
+ pointer-events: auto;
+ width: 100%; //width: 25px;
+ border-radius: 5px;
+ margin-top: 8px;
+ border-color: #d3d3d3;
+ border-style: solid;
+ border-width: thin;
+ transition: all 0.3s ease-out;
+ display: flex;
+ flex-direction: row;
+ padding: 5px;
+
+
+ &:hover{
+ border-color: #e9e9e9;
+ background-color: #6d6c6c
+ }
+
+ .hotKey-icon, .hotKey-close{
+ background-color: transparent;
+ border-radius: 10%;
+ padding: 5px;
+
+
+ &:hover{
+ background-color: #616060;
+ }
+ }
+
+ .hotKey-close{
+ right: 30px;
+ position: fixed;
+ padding-top: 10px;
+
+}
+
+ .hotkey-title{
+ top: 6px;
+ position: relative;
+ cursor: text;
+
+ }
+
+ .hotkey-title-input{
+ background-color: transparent;
+ border: none;
+ border-color: transparent;
+ outline: none;
+ cursor: text;
+
+ }
+}
+
+.hotKeyButtons {
+ position: relative;
+ width: 100%;
+
+}
+
+.hotKey-icon-button {
+
+ background-color: transparent;
+
+
+}
+
+.icon-panel {
+ position: absolute;
+ z-index: 10000;
+ border-color: black;
+ border-style: solid;
+ border-width: medium;
+ border-radius: 10%;
+ background-color: #323232;
+
+ .icon-panel-button{
+ background-color: #323232;
+ border-radius: 10%;
+
+
+ &:hover{
+ background-color:#7a7878
+ }
+ }
+
+
+
+}
+
+
// .sliderBox-outerDiv {
// width: 30%;// width: calc(100% - 14px); // 14px accounts for handles that are at the max value of the slider that would extend outside the box
// height: 40; // height: 100%;
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index b11fa3bd5..e34b66963 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -1,22 +1,161 @@
-/* eslint-disable react/jsx-props-no-spreading */
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Tooltip } from '@mui/material';
import { action, computed, makeObservable, observable, ObservableMap } from 'mobx';
-import { observer } from 'mobx-react';
+import { observer, useLocalObservable } from 'mobx-react';
import * as React from 'react';
+import { useEffect, useRef } from 'react';
import { Handles, Rail, Slider, Ticks, Tracks } from 'react-compound-slider';
import { AiOutlineMinusSquare, AiOutlinePlusSquare } from 'react-icons/ai';
import { CiCircleRemove } from 'react-icons/ci';
import { Doc, DocListCast, Field, FieldType, LinkedTo, StrListCast } from '../../fields/Doc';
+import { DocData } from '../../fields/DocSymbols';
import { Id } from '../../fields/FieldSymbols';
import { List } from '../../fields/List';
import { RichTextField } from '../../fields/RichTextField';
+import { DocCast, StrCast } from '../../fields/Types';
+import { Button, CurrentUserUtils } from '../util/CurrentUserUtils';
import { SearchUtil } from '../util/SearchUtil';
import { SnappingManager } from '../util/SnappingManager';
import { undoable } from '../util/UndoManager';
import { FieldsDropdown } from './FieldsDropdown';
import './FilterPanel.scss';
import { DocumentView } from './nodes/DocumentView';
+import { ButtonType } from './nodes/FontIconBox/FontIconBox';
import { Handle, Tick, TooltipRail, Track } from './nodes/SliderBox-components';
import { ObservableReactComponent } from './ObservableReactComponent';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
+
+interface HotKeyButtonProps {
+ hotKey: Doc;
+ selected?: Doc;
+}
+
+/**
+ * Renders the buttons that correspond to each icon tag in the properties view. Allows users to change the icon,
+ * title, and delete.
+ */
+const HotKeyIconButton: React.FC<HotKeyButtonProps> = observer(({ hotKey /*, selected */ }) => {
+ const state = useLocalObservable(() => ({
+ isActive: false,
+ isEditing: false,
+ myHotKey: hotKey,
+
+ toggleActive() { this.isActive = !this.isActive; },
+ deactivate() { this.isActive = false; },
+ startEditing() { this.isEditing = true; },
+ stopEditing() { this.isEditing = false; },
+ setHotKey(newHotKey: string) { this.myHotKey.title = newHotKey; },
+ })); // prettier-ignore
+
+ const panelRef = useRef<HTMLDivElement>(null);
+ const inputRef = useRef<HTMLInputElement>(null);
+
+ const handleClick = () => state.toggleActive();
+
+ /**
+ * Updates the list of hotkeys based on the users input. replaces the old title with the new one and then assigns this new
+ * hotkey with the current icon
+ */
+ const updateFromInput = undoable(() => {
+ hotKey.title = StrCast(state.myHotKey.title);
+ hotKey.toolTip = `Click to toggle the ${StrCast(hotKey.title)}'s group's visibility`;
+ }, '');
+
+ /**
+ * Deselects if the user clicks outside the button
+ * @param event
+ */
+ const handleClickOutside = (event: MouseEvent) => {
+ if (panelRef.current && !panelRef.current.contains(event.target as Node)) {
+ state.deactivate();
+ if (state.isEditing) {
+ state.stopEditing();
+
+ updateFromInput();
+ }
+ }
+ };
+
+ useEffect(() => {
+ document.addEventListener('mousedown', handleClickOutside);
+ return () => document.removeEventListener('mousedown', handleClickOutside);
+ }, []);
+
+ const iconOpts = ['star', 'heart', 'bolt', 'satellite', 'palette', 'robot', 'lightbulb', 'highlighter', 'book', 'chalkboard'] as IconProp[];
+
+ /**
+ * Panel of icons the user can choose from to represent their tag
+ */
+ const iconPanel = iconOpts.map(icon => (
+ <button
+ key={icon.toString()}
+ onClick={undoable(e => {
+ e.stopPropagation;
+ hotKey[DocData].icon = icon.toString();
+ }, '')}
+ className="icon-panel-button">
+ <FontAwesomeIcon icon={icon} color={SnappingManager.userColor} />
+ </button>
+ ));
+
+ /**
+ * Actually renders the buttons
+ */
+
+ return (
+ <div
+ className={`filterHotKey-button`}
+ onClick={e => {
+ e.stopPropagation();
+ state.startEditing();
+ setTimeout(() => inputRef.current?.focus(), 0);
+ }}>
+ <div className={`hotKey-icon-button ${state.isActive ? 'active' : ''}`} ref={panelRef}>
+ <Tooltip title={<div className="dash-tooltip">Click to customize this hotkey&apos;s icon</div>}>
+ <button
+ type="button"
+ className="hotKey-icon"
+ onClick={(e: React.MouseEvent) => {
+ e.stopPropagation();
+ handleClick();
+ }}>
+ <FontAwesomeIcon icon={hotKey.icon as IconProp} size="2xl" color={SnappingManager.userColor} />
+ </button>
+ </Tooltip>
+ {state.isActive && <div className="icon-panel">{iconPanel}</div>}
+ </div>
+ {state.isEditing ? (
+ <input
+ ref={inputRef}
+ type="text"
+ value={StrCast(state.myHotKey.title).toUpperCase()}
+ onChange={e => state.setHotKey(e.target.value)}
+ onBlur={() => {
+ state.stopEditing();
+ updateFromInput();
+ }}
+ onKeyDown={e => {
+ if (e.key === 'Enter') {
+ state.stopEditing();
+ updateFromInput();
+ }
+ }}
+ className="hotkey-title-input"
+ />
+ ) : (
+ <p className="hotkey-title">{StrCast(hotKey.title).toUpperCase()}</p>
+ )}
+ <button
+ className="hotKey-close"
+ onClick={(e: React.MouseEvent) => {
+ e.stopPropagation();
+ Doc.RemFromFilterHotKeys(hotKey);
+ }}>
+ <FontAwesomeIcon icon={'x' as IconProp} color={SnappingManager.userColor} />
+ </button>
+ </div>
+ );
+});
interface filterProps {
Document: Doc;
@@ -24,13 +163,16 @@ interface filterProps {
@observer
export class FilterPanel extends ObservableReactComponent<filterProps> {
- @observable _selectedFacetHeaders = new Set<string>();
+ // eslint-disable-next-line no-use-before-define
+ public static Instance: FilterPanel;
constructor(props: filterProps) {
super(props);
makeObservable(this);
+ FilterPanel.Instance = this;
}
+ @observable _selectedFacetHeaders = new Set<string>();
/**
* @returns the relevant doc according to the value of FilterBox._filterScope i.e. either the Current Dashboard or the Current Collection
*/
@@ -129,7 +271,7 @@ export class FilterPanel extends ObservableReactComponent<filterProps> {
@computed get activeRenderedFacetInfos() {
return new Set(
Array.from(new Set(Array.from(this._selectedFacetHeaders).concat(this.activeFacetHeaders))).map(facetHeader => {
- const facetValues = FilterPanel.gatherFieldValues(this.targetDocChildren, facetHeader, StrListCast(this.Document.childFilters));
+ const facetValues = facetHeader.startsWith('#') ? { strings: [] } : FilterPanel.gatherFieldValues(this.targetDocChildren, facetHeader, StrListCast(this.Document.childFilters));
let nonNumbers = 0;
let minVal = Number.MAX_VALUE;
@@ -147,7 +289,10 @@ export class FilterPanel extends ObservableReactComponent<filterProps> {
if (facetHeader === 'text') {
return { facetHeader, renderType: 'text' };
}
- if (facetHeader !== 'tags' && nonNumbers / facetValues.strings.length < 0.1) {
+ if (facetHeader.startsWith('#')) {
+ return { facetHeader, renderType: 'togglebox' };
+ }
+ if (facetHeader !== 'tags' && !facetHeader.startsWith('#') && nonNumbers / facetValues.strings.length < 0.1) {
const extendedMinVal = minVal - Math.min(1, Math.floor(Math.abs(maxVal - minVal) * 0.1));
const extendedMaxVal = Math.max(minVal + 1, maxVal + Math.min(1, Math.ceil(Math.abs(maxVal - minVal) * 0.05)));
const ranged: number[] | undefined = Doc.readDocRangeFilter(this.Document, facetHeader); // not the filter range, but the zooomed in range on the filter
@@ -192,21 +337,17 @@ export class FilterPanel extends ObservableReactComponent<filterProps> {
const allCollectionDocs = new Set<Doc>();
SearchUtil.foreachRecursiveDoc(this.targetDocChildren, (depth: number, doc: Doc) => allCollectionDocs.add(doc));
const set = new Set<string>([...StrListCast(this.Document.childFilters).map(filter => filter.split(Doc.FilterSep)[1]), Doc.FilterNone, Doc.FilterAny]);
- if (facetHeader === 'tags')
- allCollectionDocs.forEach(child =>
- StrListCast(child[facetHeader])
- .filter(h => h)
- .forEach(key => set.add(key))
- );
- else
- allCollectionDocs.forEach(child => {
- const fieldVal = child[facetHeader] as FieldType;
- if (!(fieldVal instanceof List)) {
- // currently we have no good way of filtering based on a field that is a list
- set.add(Field.toString(fieldVal));
- (fieldVal === true || fieldVal === false) && set.add((!fieldVal).toString());
- }
- });
+
+ allCollectionDocs.forEach(child => {
+ const fieldVal = child[facetHeader] as FieldType;
+ const fieldStrList = StrListCast(child[facetHeader]).filter(h => h);
+ if (fieldStrList.length) fieldStrList.forEach(key => set.add(key));
+ else if (!(fieldVal instanceof List)) {
+ // currently we have no good way of filtering based on a field that is a list
+ set.add(Field.toString(fieldVal));
+ (fieldVal === true || fieldVal === false) && set.add((!fieldVal).toString());
+ }
+ });
const facetValues = Array.from(set).filter(v => v);
let nonNumbers = 0;
@@ -215,12 +356,59 @@ export class FilterPanel extends ObservableReactComponent<filterProps> {
return nonNumbers / facetValues.length > 0.1 ? facetValues.sort() : facetValues.sort((n1: string, n2: string) => Number(n1) - Number(n2));
};
+ /**
+ * Allows users to add a filter hotkey to the properties panel. Will also update the multitoggle at the top menu and the
+ * icontags tht are displayed on the documents themselves
+ * @param hotKey tite of the new hotkey
+ */
+ addHotkey = (hotKey: string) => {
+ const buttons = DocCast(Doc.UserDoc().myContextMenuBtns);
+ const filter = DocCast(buttons.Filter);
+ const title = hotKey.startsWith('#') ? hotKey.substring(1) : hotKey;
+
+ const newKey: Button = {
+ title,
+ icon: 'question',
+ toolTip: `Click to toggle the ${title}'s group's visibility`,
+ btnType: ButtonType.ToggleButton,
+ expertMode: false,
+ toolType: '#' + title,
+ funcs: {},
+ scripts: { onClick: '{ return handleTags(this.toolType, _readOnly_);}' },
+ };
+
+ const newBtn = CurrentUserUtils.setupContextMenuBtn(newKey, filter);
+ newBtn.isSystem = newBtn[DocData].isSystem = undefined;
+
+ Doc.AddToFilterHotKeys(newBtn);
+ };
+
+ /**
+ * Renders the newly formed hotkey icon buttons
+ * @returns the buttons to be rendered
+ */
+ hotKeyButtons = () => {
+ const selected = DocumentView.SelectedDocs().lastElement();
+ const hotKeys = Doc.MyFilterHotKeys;
+
+ // Selecting a button should make it so that the icon on the top filter panel becomes said icon
+ const buttons = hotKeys.map(hotKey => (
+ <Tooltip key={StrCast(hotKey.title)} title={<div className="dash-tooltip">Click to customize this hotkey&apos;s icon</div>}>
+ <HotKeyIconButton hotKey={hotKey} selected={selected} />
+ </Tooltip>
+ ));
+
+ return buttons;
+ };
+
+ // @observable iconPanelMap: Map<string, number> = new Map();
+
render() {
return (
<div className="filterBox-treeView">
<div className="filterBox-select">
<div style={{ width: '100%' }}>
- <FieldsDropdown Document={this.Document} selectFunc={this.facetClick} showPlaceholder placeholder="add a filter" addedFields={['acl_Guest', LinkedTo]} />
+ <FieldsDropdown Document={this.Document} selectFunc={this.facetClick} showPlaceholder placeholder="add a filter" addedFields={['acl_Guest', LinkedTo, 'Star', 'Heart', 'Bolt', 'Cloud']} />
</div>
{/* THE FOLLOWING CODE SHOULD BE DEVELOPER FOR BOOLEAN EXPRESSION (AND / OR) */}
{/* <div className="filterBox-select-bool">
@@ -281,6 +469,15 @@ export class FilterPanel extends ObservableReactComponent<filterProps> {
)
)}
</div>
+ <div>
+ <div className="filterBox-select">
+ <div style={{ width: '100%' }}>
+ <FieldsDropdown Document={this.Document} selectFunc={this.addHotkey} showPlaceholder placeholder="add a hotkey" addedFields={['acl_Guest', LinkedTo]} />
+ </div>
+ </div>
+ </div>
+
+ <div>{this.hotKeyButtons()}</div>
</div>
);
}
@@ -321,6 +518,22 @@ export class FilterPanel extends ObservableReactComponent<filterProps> {
</div>
);
});
+ case 'togglebox':
+ return (
+ <div>
+ <input
+ style={{ width: 20, marginLeft: 20 }}
+ checked={['check', 'exists'].includes(
+ StrListCast(this.Document._childFilters)
+ .find(filter => filter.split(Doc.FilterSep)[0] === 'tags' && filter.split(Doc.FilterSep)[1] === facetHeader)
+ ?.split(Doc.FilterSep)[2] ?? ''
+ )}
+ type={'checkbox'}
+ onChange={undoable(e => Doc.setDocFilter(this.Document, 'tags', facetHeader, e.target.checked ? 'check' : 'remove'), 'set filter')}
+ />
+ -set-
+ </div>
+ );
case 'range':
{
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 2adeefa37..41a933431 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -3,7 +3,7 @@ import { faBuffer, faHireAHelper } from '@fortawesome/free-brands-svg-icons';
import * as far from '@fortawesome/free-regular-svg-icons';
import * as fa from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, configure, makeObservable, observable, reaction, runInAction } from 'mobx';
+import { action, computed, configure, makeObservable, observable, reaction, runInAction, trace } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import ResizeObserver from 'resize-observer-polyfill';
@@ -556,6 +556,10 @@ export class MainView extends ObservableReactComponent<object> {
fa.faRobot,
fa.faSatellite,
fa.faStar,
+ fa.faCloud,
+ fa.faBolt,
+ fa.faLightbulb,
+ fa.faX,
]
);
}
@@ -720,8 +724,8 @@ export class MainView extends ObservableReactComponent<object> {
setupMoveUpEvents(
this,
e,
- action(() => {
- SnappingManager.SetPropertiesWidth(Math.max(0, this._dashUIWidth - e.clientX));
+ action(moveEv => {
+ SnappingManager.SetPropertiesWidth(Math.max(0, this._dashUIWidth - moveEv.clientX));
return !SnappingManager.PropertiesWidth;
}),
action(() => {
@@ -820,6 +824,7 @@ export class MainView extends ObservableReactComponent<object> {
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
+ dontCenter="y"
/>
</div>
);
@@ -845,6 +850,7 @@ export class MainView extends ObservableReactComponent<object> {
};
@computed get mainInnerContent() {
+ trace();
const leftMenuFlyoutWidth = this._leftMenuFlyoutWidth + this.leftMenuWidth();
const width = this.propertiesWidth() + leftMenuFlyoutWidth;
return (
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index f346d4ba8..f96a4a255 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -246,26 +246,6 @@ export class PropertiesButtons extends React.Component {
// );
// }
- // @computed get freezeThumb() {
- // return this.propertyToggleBtn(
- // 'FreezeThumb',
- // '_thumb-frozen',
- // on => `${on ? 'Freeze' : 'Unfreeze'} thumbnail`,
- // on => 'snowflake',
- // (dv, doc) => {
- // if (doc['thumb-frozen']) doc['thumb-frozen'] = undefined;
- // else {
- // document.body.focus(); // so that we can access the clipboard without an error
- // setTimeout(() =>
- // pasteImageBitmap((data_url: any, error: any) => {
- // error && console.log(error);
- // data_url && Utils.convertDataUri(data_url, doc[Id] + '-thumb-frozen', true).then(returnedfilename => (doc['thumb-frozen'] = new ImageField(returnedfilename)));
- // })
- // );
- // }
- // }
- // );
- // }
@computed get snapButton() {
// THESE ARE NOT COMING
return this.propertyToggleBtn(
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 39ed16f5d..fcac4d464 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -58,7 +58,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
private _widthUndo?: UndoManager.Batch;
// eslint-disable-next-line no-use-before-define
- public static Instance: PropertiesView | undefined;
+ public static Instance: PropertiesView;
constructor(props: PropertiesViewProps) {
super(props);
makeObservable(this);
@@ -1277,7 +1277,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
@computed get filtersSubMenu() {
return (
// prettier-ignore
- <PropertiesSection title="Filters" isOpen={this.openFilters} setIsOpen={bool => { this.openFilters = bool; }} onDoubleClick={this.CloseAll}>
+ <PropertiesSection title="Filters" isOpen={this.openFilters} setIsOpen={action(bool => { this.openFilters = bool; })} onDoubleClick={this.CloseAll}>
<div className="propertiesView-content filters" style={{ position: 'relative', height: 'auto' }}>
<FilterPanel Document={this.selectedDoc ?? Doc.ActiveDashboard!} />
</div>
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 8f0a35df0..dd60bfa65 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -246,6 +246,7 @@ export class SidebarAnnos extends ObservableReactComponent<FieldViewProps & Extr
isAnnotationOverlay={false}
select={emptyFunction}
NativeDimScaling={returnOne}
+ dontCenter="y"
// childlayout_showTitle={this.layout_showTitle}
isAnyChildContentActive={returnFalse}
childDocumentsActive={this._props.isContentActive}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 76cb119ab..3545afcee 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -19,12 +19,11 @@ import { SnappingManager } from '../util/SnappingManager';
import { undoable, UndoManager } from '../util/UndoManager';
import { TreeSort } from './collections/TreeSort';
import { Colors } from './global/globalEnums';
-import { TagsView } from './TagsView';
-import { CollectionFreeFormDocumentView } from './nodes/CollectionFreeFormDocumentView';
import { DocumentView, DocumentViewProps } from './nodes/DocumentView';
import { FieldViewProps } from './nodes/FieldView';
import { StyleProp } from './StyleProp';
import './StyleProvider.scss';
+import { TagsView } from './TagsView';
function toggleLockedPosition(doc: Doc) {
UndoManager.RunInBatch(() => Doc.toggleLockedPosition(doc), 'toggleBackground');
@@ -325,7 +324,6 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
type={Type.TERT}
dropdownType={DropdownType.CLICK}
fillWidth
- // eslint-disable-next-line react/no-unstable-nested-components
iconProvider={() => <div className='styleProvider-filterShift'><FaFilter/></div>}
closeOnSelect
setSelectedVal={((dvValue: unknown) => {
@@ -365,7 +363,8 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
</Tooltip>
);
};
- const tags = () => props?.DocumentView?.() && CollectionFreeFormDocumentView.from(props.DocumentView()) ? <TagsView View={props.DocumentView()}/> : null;
+ const tags = () => docView?.() ? <TagsView Views={[docView?.()]}/> : null;
+
return (
<>
{paint()}
diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx
index 0ac015b36..f44fd1d03 100644
--- a/src/client/views/TagsView.tsx
+++ b/src/client/views/TagsView.tsx
@@ -18,6 +18,8 @@ import { ObservableReactComponent } from './ObservableReactComponent';
import './TagsView.scss';
import { DocumentView } from './nodes/DocumentView';
import { FaceRecognitionHandler } from './search/FaceRecognitionHandler';
+import { IconTagBox } from './nodes/IconTagBox';
+import { Id } from '../../fields/FieldSymbols';
/**
* The TagsView is a metadata input/display panel shown at the bottom of a DocumentView in a freeform collection.
@@ -27,13 +29,13 @@ import { FaceRecognitionHandler } from './search/FaceRecognitionHandler';
* the user can drag them off in order to display a collection of all documents that share the tag value.
*
* The tags that are added using the panel are the same as the #tags that can entered in a text Doc.
- * Note that tags starting with #@ display a metadata key/value pair instead of the tag itself.
- * e.g., '#@author' shows the document author
+ * Note that tags starting with @ display a metadata key/value pair instead of the tag itself.
+ * e.g., '@author' shows the document author
*
*/
interface TagItemProps {
- doc: Doc;
+ docs: Doc[];
tag: string;
tagDoc: Opt<Doc>;
showRemoveUI: boolean;
@@ -59,7 +61,7 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
* @param tag tag string
* @returns tag collection Doc or undefined
*/
- public static findTagCollectionDoc = (tag: String) => TagItem.AllTagCollectionDocs.find(doc => doc.title === tag);
+ public static findTagCollectionDoc = (tag: string) => TagItem.AllTagCollectionDocs.find(doc => doc.title === tag);
/**
* Creates a Doc that collects Docs with the specified tag / value
@@ -82,6 +84,9 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
*/
public static allDocsWithTag = (tag: string) => DocListCast(TagItem.findTagCollectionDoc(tag)?.[DocData].docs);
+ public static docHasTag = (doc: Doc, tag: string) => {
+ return StrListCast(doc?.tags).includes(tag);
+ };
/**
* Adds a tag to the metadata of this document and adds the Doc to the corresponding tag collection Doc (or creates it)
* @param tag tag string
@@ -91,7 +96,7 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
const tagCollection = TagItem.findTagCollectionDoc(tag) ?? TagItem.createTagCollectionDoc(tag);
// If the document is of type COLLECTION, make it a smart collection, otherwise, add the tag to the document.
- if (doc.type === DocumentType.COL) {
+ if (doc.type === DocumentType.COL && !doc.annotationOn) {
Doc.AddDocToList(tagCollection[DocData], 'collections', doc);
// Iterate through the tag Doc collections and add a copy of the document to each collection
@@ -148,7 +153,7 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
private _ref: React.RefObject<HTMLDivElement>;
- constructor(props: any) {
+ constructor(props: TagItemProps) {
super(props);
makeObservable(this);
this._ref = React.createRef();
@@ -172,12 +177,12 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
docData.data = new List<Doc>(newEmbeddings);
docData.title = this._props.tag;
docData.tags = new List<string>([this._props.tag]);
- docData.showTags = true;
docData.freeform_fitContentsToBox = true;
doc._freeform_panX = doc._freeform_panY = 0;
doc._width = 900;
doc._height = 900;
doc.layout_fitWidth = true;
+ doc._layout_showTags = true;
return doc;
})(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
newEmbeddings.forEach(embed => Doc.SetContainer(embed, newCollection));
@@ -202,29 +207,45 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
return false;
},
returnFalse,
- emptyFunction
+ clickEv => {
+ clickEv.stopPropagation();
+ this._props.setToEditing();
+ }
);
e.preventDefault();
};
+ @computed get doc() {
+ return this._props.docs.lastElement();
+ }
+
render() {
- this._props.tagDoc && setTimeout(() => TagItem.addTagToDoc(this._props.doc, this._props.tag)); // bcz: hack to make sure that Docs are added to their tag Doc collection since metadata can get set anywhere without a guard triggering an add to the collection
- const tag = this._props.tag.replace(/^#/, '');
- const metadata = tag.startsWith('@') ? tag.replace(/^@/, '') : '';
+ this._props.tagDoc && setTimeout(() => this._props.docs.forEach(doc => TagItem.addTagToDoc(doc, this._props.tag))); // bcz: hack to make sure that Docs are added to their tag Doc collection since metadata can get set anywhere without a guard triggering an add to the collection
+ const metadata = this._props.tag.startsWith('@') ? this._props.tag.replace(/^@/, '') : '';
return (
- <div className={'tagItem' + (!this._props.tagDoc ? ' faceItem' : '')} onClick={this._props.setToEditing} onPointerDown={this.handleDragStart} ref={this._ref}>
+ <div className={'tagItem' + (!this._props.tagDoc ? ' faceItem' : '')} onPointerDown={this.handleDragStart} ref={this._ref}>
{metadata ? (
<span>
- <b style={{ fontSize: 'smaller' }}>{tag}&nbsp;</b>
- {Field.toString(this._props.doc[metadata])}
+ <b style={{ fontSize: 'smaller' }}>{'@' + metadata}&nbsp;</b>
+ {typeof this.doc[metadata] === 'boolean' ? (
+ <input
+ type="checkbox"
+ onClick={e => e.stopPropagation()}
+ onPointerDown={e => e.stopPropagation()}
+ onChange={undoable(() => (this.doc[metadata] = !this.doc[metadata]), 'metadata toggle')}
+ checked={this.doc[metadata] as boolean}
+ />
+ ) : (
+ Field.toString(this.doc[metadata])
+ )}
</span>
) : (
- tag
+ this._props.tag
)}
{this.props.showRemoveUI && this._props.tagDoc && (
<IconButton
tooltip="Remove tag"
- onPointerDown={undoable(() => TagItem.removeTagFromDoc(this._props.doc, this._props.tag, this._props.tagDoc), `remove tag ${this._props.tag}`)}
+ onPointerDown={undoable(() => this._props.docs.forEach(doc => TagItem.removeTagFromDoc(doc, this._props.tag, this._props.tagDoc)), `remove tag ${this._props.tag}`)}
icon={<FontAwesomeIcon icon="times" size="sm" />}
style={{ width: '8px', height: '8px', marginLeft: '10px' }}
/>
@@ -235,7 +256,7 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
}
interface TagViewProps {
- View: DocumentView;
+ Views: DocumentView[];
}
/**
@@ -243,20 +264,21 @@ interface TagViewProps {
*/
@observer
export class TagsView extends ObservableReactComponent<TagViewProps> {
- constructor(props: any) {
+ constructor(props: TagViewProps) {
super(props);
makeObservable(this);
}
+ InsetDist = 25; // how far tag panel is moved up to overlap DocumentView.
@observable _panelHeightDirty = 0;
@observable _currentInput = '';
- @observable _isEditing = !StrListCast(this._props.View.dataDoc.tags).length;
+ @observable _isEditing = !StrListCast(this.View.dataDoc.tags).length;
_heightDisposer: IReactionDisposer | undefined;
componentDidMount() {
this._heightDisposer = reaction(
- () => this._props.View.screenToContentsTransform(),
- xf => {
+ () => this.View.screenToContentsTransform(),
+ () => {
this._panelHeightDirty = this._panelHeightDirty + 1;
}
);
@@ -265,11 +287,21 @@ export class TagsView extends ObservableReactComponent<TagViewProps> {
this._heightDisposer?.();
}
+ @computed get View() {
+ return this._props.Views.lastElement();
+ }
+
+ // x: 1 => 1/vs 0 => 1 1/(vs - (1-x)*(vs-1))
@computed get currentScale() {
- return NumCast(DocCast(this._props.View.Document.embedContainer)?._freeform_scale, 1);
+ if (this._props.Views.length > 1) return 1;
+ const x = NumCast(this.View.Document.height) / this.View.screenToContentsTransform().Scale / 80;
+ const xscale = x >= 1 ? 0 : 1 / (1 + x * (this.View.screenToLocalScale() - 1)); //docheight / this.View.screenToContentsTransform().Scale / 35 / this.View.screenToLocalScale() - ;
+ const y = NumCast(this.View.Document.width) / this.View.screenToContentsTransform().Scale / 200;
+ const yscale = y >= 1 ? 0 : 1 / (1 + y * (this.View.screenToLocalScale() - 1)); //docheight / this.View.screenToContentsTransform().Scale / 35 / this.View.screenToLocalScale() - ;
+ return Math.max(xscale, yscale, 1 / this.View.screenToLocalScale());
}
@computed get isEditing() {
- return this._isEditing && DocumentView.SelectedDocs().includes(this._props.View.Document);
+ return this._isEditing && (this._props.Views.length > 1 || (DocumentView.Selected().length === 1 && DocumentView.Selected().includes(this.View)));
}
/**
@@ -279,61 +311,89 @@ export class TagsView extends ObservableReactComponent<TagViewProps> {
@action
setToEditing = (editing = true) => {
this._isEditing = editing;
- editing && this._props.View.select(false);
+ editing && this._props.Views.length === 1 && this.View.select(false);
};
/**
- * Adds the specified tag to the Doc. If the tag is not prefixed with '#', then a '#' prefix is added.
- * Whne the tag (after the '#') begins with '@', then a metadata key/value pair is displayed instead of
- * just the tag.
- * @param tag tag string to add
+ * Adds the specified tag or metadata to the Doc. If the tag is not prefixed with '#', then a '#' prefix is added.
+ * When the tag (after the '#') begins with '@', then a metadata key/value pair is displayed instead of
+ * just the tag. In addition, a suffix of :<value> can be added to set a metadata value
+ * @param tag tag string to add (format: #<tag> | #@field(:(=)?value)? )
*/
submitTag = undoable(
action((tag: string) => {
- const submittedLabel = tag.trim();
- submittedLabel && TagItem.addTagToDoc(this._props.View.Document, '#' + submittedLabel.replace(/^#/, ''));
+ const submittedLabel = tag.trim().replace(/^#/, '').split(':');
+ if (submittedLabel[0]) {
+ this._props.Views.forEach(view => {
+ TagItem.addTagToDoc(view.Document, (submittedLabel[0].startsWith('@') ? '' : '#') + submittedLabel[0]);
+ if (submittedLabel.length > 1) Doc.SetField(view.Document, submittedLabel[0].replace(/^@/, ''), ':' + submittedLabel[1]);
+ });
+ }
this._currentInput = ''; // Clear the input box
}),
'added doc label'
);
/**
- * When 'showTags' is set on a Doc, this displays a wrapping panel of tagItemViews corresponding to all the tags set on the Doc).
+ * When 'layout_showTags' is set on a Doc, this displays a wrapping panel of tagItemViews corresponding to all the tags set on the Doc).
* When the dropdown is clicked, this will toggle an extended UI that allows additional tags to be added/removed.
*/
render() {
- const tagsList = new Set<string>(StrListCast(this._props.View.dataDoc.tags));
- const chatTagsList = new Set<string>(StrListCast(this._props.View.dataDoc.tags_chat));
+ const tagsList = new Set<string>(StrListCast(this.View.dataDoc.tags));
+ const chatTagsList = new Set<string>(StrListCast(this.View.dataDoc.tags_chat));
const facesList = new Set<string>(
- DocListCast(this._props.View.dataDoc[Doc.LayoutFieldKey(this._props.View.Document) + '_annotations'])
- .concat(this._props.View.Document)
+ DocListCast(this.View.dataDoc[Doc.LayoutFieldKey(this.View.Document) + '_annotations'])
+ .concat(this.View.Document)
.filter(d => d.face)
.map(doc => StrCast(DocCast(doc.face)?.title))
);
this._panelHeightDirty;
- return !this._props.View.Document.showTags ? null : (
+ return this.View.ComponentView?.isUnstyledView?.() || (!this.View.showTags && this._props.Views.length === 1) ? null : (
<div
className="tagsView-container"
- ref={r => r && new ResizeObserver(action(() => (this._props.View.TagPanelHeight = r?.getBoundingClientRect().height ?? 0))).observe(r)}
+ ref={r => r && new ResizeObserver(action(() => this._props.Views.length === 1 && (this.View.TagPanelHeight = Math.max(0, (r?.getBoundingClientRect().height ?? 0) - this.InsetDist)))).observe(r)}
style={{
+ display: SnappingManager.IsResizing === this.View.Document[Id] ? 'none' : undefined,
transformOrigin: 'top left',
maxWidth: `${100 * this.currentScale}%`,
width: 'max-content',
transform: `scale(${1 / this.currentScale})`,
backgroundColor: this.isEditing ? Colors.LIGHT_GRAY : Colors.TRANSPARENT,
borderColor: this.isEditing ? Colors.BLACK : Colors.TRANSPARENT,
+ position: 'relative',
+ top: this._props.Views.length > 1 ? 25 : `calc(-${this.InsetDist} * ${1 / this.currentScale}px)`,
}}>
<div className="tagsView-content" style={{ width: '100%' }}>
<div className="tagsView-list">
- {!tagsList.size && !facesList.size ? null : ( //
- <IconButton style={{ width: '8px' }} tooltip="Close Menu" onPointerDown={() => this.setToEditing(!this._isEditing)} icon={<FontAwesomeIcon icon={this._isEditing ? 'chevron-up' : 'chevron-down'} size="sm" />} />
+ {this._props.Views.length === 1 && !this.View.showTags ? null : ( //
+ <IconButton
+ style={{ width: '8px' }}
+ tooltip="Close Menu"
+ onPointerDown={e =>
+ setupMoveUpEvents(this, e, returnFalse, emptyFunction, upEv => {
+ this.setToEditing(!this._isEditing);
+ upEv.stopPropagation();
+ })
+ }
+ icon={<FontAwesomeIcon icon={this._isEditing ? 'chevron-up' : 'chevron-down'} size="sm" />}
+ />
)}
- {Array.from(tagsList).map((tag, i) => (
- <TagItem key={i} doc={this._props.View.Document} tag={tag} tagDoc={TagItem.findTagCollectionDoc(tag) ?? TagItem.createTagCollectionDoc(tag)} setToEditing={this.setToEditing} showRemoveUI={this.isEditing} />
- ))}
- {Array.from(facesList).map((tag, i) => (
- <TagItem key={i} doc={this._props.View.Document} tag={tag} tagDoc={undefined} setToEditing={this.setToEditing} showRemoveUI={this.isEditing} />
+ <IconTagBox Views={this._props.Views} IsEditing={this._isEditing} />
+ {Array.from(tagsList)
+ .filter(tag => (tag.startsWith('#') || tag.startsWith('@')) && !Doc.MyFilterHotKeys.some(key => key.toolType === tag))
+ .map(tag => (
+ <TagItem
+ key={tag}
+ docs={this._props.Views.map(view => view.Document)}
+ tag={tag}
+ tagDoc={TagItem.findTagCollectionDoc(tag) ?? TagItem.createTagCollectionDoc(tag)}
+ setToEditing={this.setToEditing}
+ showRemoveUI={this.isEditing}
+ />
+ ))}
+ {Array.from(facesList).map(tag => (
+ <TagItem key={tag} docs={this._props.Views.map(view => view.Document)} tag={tag} tagDoc={undefined} setToEditing={this.setToEditing} showRemoveUI={this.isEditing} />
))}
</div>
{this.isEditing ? (
@@ -355,9 +415,9 @@ export class TagsView extends ObservableReactComponent<TagViewProps> {
/>
</div>
<div className="tagsView-suggestions-box">
- {TagItem.AllTagCollectionDocs.map((doc, i) => {
- const tag = StrCast(doc.title);
- return (
+ {TagItem.AllTagCollectionDocs.map(doc => StrCast(doc.title))
+ .filter(tag => (tag.startsWith('#') || tag.startsWith('@')) && !Doc.MyFilterHotKeys.some(key => key.toolType === tag))
+ .map(tag => (
<Button
style={{ margin: '2px 2px', border: '1px solid black', backgroundColor: 'lightblue', color: 'black' }}
text={tag}
@@ -366,20 +426,17 @@ export class TagsView extends ObservableReactComponent<TagViewProps> {
onClick={() => this.submitTag(tag)}
key={tag}
/>
- );
- })}
- {Array.from(chatTagsList).map(tag => {
- return (
- <Button
- style={{ margin: '2px 2px', border: '1px solid black', backgroundColor: 'lightpink', color: 'black' }}
- text={tag}
- color={SnappingManager.userVariantColor}
- tooltip="Add existing tag"
- onClick={() => this.submitTag(tag)}
- key={tag}
- />
- );
- })}
+ ))}
+ {Array.from(chatTagsList).map(tag => (
+ <Button
+ style={{ margin: '2px 2px', border: '1px solid black', backgroundColor: 'lightpink', color: 'black' }}
+ text={tag}
+ color={SnappingManager.userVariantColor}
+ tooltip="Add existing tag"
+ onClick={() => this.submitTag(tag)}
+ key={tag}
+ />
+ ))}
</div>
</div>
) : null}
diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx
index 9eb16917b..0ea9f8ebc 100644
--- a/src/client/views/collections/CollectionCalendarView.tsx
+++ b/src/client/views/collections/CollectionCalendarView.tsx
@@ -38,8 +38,8 @@ export class CollectionCalendarView extends CollectionSubView() {
const aDateRangeStr = StrCast(DocListCast(calendarA.data).lastElement()?.date_range);
const bDateRangeStr = StrCast(DocListCast(calendarB.data).lastElement()?.date_range);
- const [aFromDate, aToDate] = dateRangeStrToDates(aDateRangeStr);
- const [bFromDate, bToDate] = dateRangeStrToDates(bDateRangeStr);
+ const { start: aFromDate, end: aToDate } = dateRangeStrToDates(aDateRangeStr);
+ const { start: bFromDate, end: bToDate } = dateRangeStrToDates(bDateRangeStr);
if (aFromDate > bFromDate) {
return -1; // a comes first
@@ -82,6 +82,7 @@ export class CollectionCalendarView extends CollectionSubView() {
isAnnotationOverlay={false}
// select={emptyFunction} What does this mean?
isAnyChildContentActive={returnTrue} // ??
+ dontCenter="y"
// childDocumentsActive={}
// whenChildContentsActiveChanged={}
childHideDecorationTitle={false}
diff --git a/src/client/views/collections/CollectionCardDeckView.scss b/src/client/views/collections/CollectionCardDeckView.scss
index a089b248d..d1731c244 100644
--- a/src/client/views/collections/CollectionCardDeckView.scss
+++ b/src/client/views/collections/CollectionCardDeckView.scss
@@ -6,12 +6,15 @@
position: relative;
background-color: white;
overflow: hidden;
+
+ button {
+ border-radius: 50%;
+ }
}
.card-wrapper {
display: grid;
grid-template-columns: repeat(10, 1fr);
- // width: 100%;
transform-origin: top left;
position: absolute;
@@ -22,54 +25,18 @@
transition: transform 0.3s cubic-bezier(0.455, 0.03, 0.515, 0.955);
}
-.card-button-container {
- display: flex;
- padding: 3px;
- // width: 300px;
- background-color: rgb(218, 218, 218); /* Background color of the container */
- border-radius: 50px; /* Rounds the corners of the container */
- transform: translateY(75px);
- // box-shadow: 0 4px 8px rgba(0,0,0,0.1); /* Optional: Adds shadow for depth */
- align-items: center; /* Centers buttons vertically */
- justify-content: start; /* Centers buttons horizontally */
-}
-
-button {
- width: 35px;
- height: 35px;
- border-radius: 50%;
- background-color: $dark-gray;
- // border-color: $medium-blue;
- margin: 5px; // transform: translateY(-50px);
+.no-card-span {
+ position: relative;
+ width: fit-content;
+ text-align: center;
+ font-size: 65px;
}
-// button:hover {
-// transform: translateY(-50px);
-// }
-
-// .card-wrapper::after {
-// content: "";
-// width: 100%; /* Forces wrapping */
-// }
-
-// .card-wrapper > .card-item:nth-child(10n)::after {
-// content: "";
-// width: 100%; /* Forces wrapping after every 10th item */
-// }
-
-// .card-row{
-// display: flex;
-// position: absolute;
-// align-items: center;
-// transition: transform 0.3s cubic-bezier(0.455, 0.03, 0.515, 0.955);
-
-// }
-
.card-item-inactive,
.card-item-active,
.card-item {
position: relative;
- transition: transform 0.5s ease-in-out;
+ transition: transform 0.3s ease-in-out;
display: flex;
flex-direction: column;
}
@@ -79,6 +46,5 @@ button {
}
.card-item-active {
- position: absolute;
z-index: 100;
}
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index 28a769896..d9c27254a 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -2,19 +2,23 @@ import { IReactionDisposer, ObservableMap, action, computed, makeObservable, obs
import { observer } from 'mobx-react';
import * as React from 'react';
import { ClientUtils, DashColor, returnFalse, returnZero } from '../../../ClientUtils';
-import { numberRange } from '../../../Utils';
-import { Doc, NumListCast } from '../../../fields/Doc';
+import { emptyFunction } from '../../../Utils';
+import { Doc } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
-import { BoolCast, Cast, DateCast, NumCast, RTFCast, ScriptCast, StrCast } from '../../../fields/Types';
+import { List } from '../../../fields/List';
+import { BoolCast, DateCast, DocCast, NumCast, RTFCast, ScriptCast, StrCast } from '../../../fields/Types';
import { URLField } from '../../../fields/URLField';
import { gptImageLabel } from '../../apis/gpt/GPT';
import { DocumentType } from '../../documents/DocumentTypes';
import { DragManager } from '../../util/DragManager';
+import { dropActionType } from '../../util/DropActionTypes';
+import { SelectionManager } from '../../util/SelectionManager';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
import { undoable } from '../../util/UndoManager';
import { StyleProp } from '../StyleProp';
+import { TagItem } from '../TagsView';
import { DocumentView } from '../nodes/DocumentView';
import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup';
import './CollectionCardDeckView.scss';
@@ -25,24 +29,30 @@ enum cardSortings {
Type = 'type',
Color = 'color',
Custom = 'custom',
+ Chat = 'chat',
+ Tag = 'tag',
None = '',
}
+
+/**
+ * New view type specifically for studying more dynamically. Allows you to reorder docs however you see fit, easily
+ * sort and filter using presets, and customize your experience with chat gpt.
+ *
+ * This file contains code as to how the docs are to be rendered (there place geographically and also in regards to sorting),
+ * and callback functions for the gpt popup
+ */
@observer
export class CollectionCardView extends CollectionSubView() {
private _dropDisposer?: DragManager.DragDropDisposer;
- private _childDocumentWidth = 600; // target width of a Doc...
private _disposers: { [key: string]: IReactionDisposer } = {};
private _textToDoc = new Map<string, Doc>();
@observable _forceChildXf = false;
- @observable _isLoading = false;
@observable _hoveredNodeIndex = -1;
@observable _docRefs = new ObservableMap<Doc, DocumentView>();
@observable _maxRowCount = 10;
-
- static getButtonGroup(groupFieldKey: 'chat' | 'star' | 'idea' | 'like', doc: Doc): number | undefined {
- return Cast(doc[groupFieldKey], 'number', null);
- }
+ @observable _docDraggedIndex: number = -1;
+ @observable overIndex: number = -1;
static imageUrlToBase64 = async (imageUrl: string): Promise<string> => {
try {
@@ -61,22 +71,46 @@ export class CollectionCardView extends CollectionSubView() {
}
};
+ constructor(props: SubCollectionViewProps) {
+ super(props);
+ makeObservable(this);
+ this.setRegenerateCallback();
+ }
protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
this._dropDisposer?.();
if (ele) {
this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
}
};
+ /**
+ * Callback to ensure gpt's text versions of the child docs are updated
+ */
+ setRegenerateCallback = () => GPTPopup.Instance.setRegenerateCallback(this.childPairStringListAndUpdateSortDesc);
- constructor(props: SubCollectionViewProps) {
- super(props);
- makeObservable(this);
- }
+ /**
+ * update's gpt's doc-text list and initializes callbacks
+ */
+ @action
+ childPairStringListAndUpdateSortDesc = async () => {
+ const sortDesc = await this.childPairStringList(); // Await the promise to get the string result
+ GPTPopup.Instance.setSortDesc(sortDesc.join());
+ GPTPopup.Instance.onSortComplete = (sortResult: string, questionType: string, tag?: string) => this.processGptOutput(sortResult, questionType, tag);
+ GPTPopup.Instance.onQuizRandom = () => this.quizMode();
+ };
+
+ componentDidMount() {
+ this.Document.childFilters_boolean = 'OR'; // bcz: really shouldn't be assigning to fields from within didMount -- this should be a default/override beahavior somehow
- componentDidMount(): void {
+ // Reaction to cardSort changes
this._disposers.sort = reaction(
- () => ({ cardSort: this.cardSort, field: this.cardSort_customField }),
- ({ cardSort, field }) => (cardSort === cardSortings.Custom && field === 'chat' ? this.openChatPopup() : GPTPopup.Instance.setVisible(false))
+ () => GPTPopup.Instance.visible,
+ isVis => {
+ if (isVis) {
+ this.openChatPopup();
+ } else {
+ this.Document.cardSort = this.cardSort === cardSortings.Chat ? '' : this.Document.cardSort;
+ }
+ }
);
}
@@ -85,56 +119,40 @@ export class CollectionCardView extends CollectionSubView() {
this._dropDisposer?.();
}
- @computed get cardSort_customField() {
- return StrCast(this.Document.cardSort_customField) as 'chat' | 'star' | 'idea' | 'like';
- }
-
@computed get cardSort() {
return StrCast(this.Document.cardSort) as cardSortings;
}
+
+ /**
+ * The child documents to be rendered-- either all of them except the Links or the docs in the currently active
+ * custom group
+ */
+ @computed get childDocsWithoutLinks() {
+ return this.childDocs.filter(l => l.type !== DocumentType.LINK);
+ }
+
/**
* how much to scale down the contents of the view so that everything will fit
*/
@computed get fitContentScale() {
const length = Math.min(this.childDocsWithoutLinks.length, this._maxRowCount);
- return (this._childDocumentWidth * length) / this._props.PanelWidth();
- }
-
- @computed get translateWrapperX() {
- let translate = 0;
-
- if (this.inactiveDocs().length !== this.childDocsWithoutLinks.length && this.inactiveDocs().length < 10) {
- translate += this.panelWidth() / 2;
- }
- return translate;
+ return (this.childPanelWidth() * length) / this._props.PanelWidth();
}
/**
- * The child documents to be rendered-- either all of them except the Links or the docs in the currently active
- * custom group
+ * When in quiz mode, randomly selects a document
*/
- @computed get childDocsWithoutLinks() {
- const regularDocs = this.childDocs.filter(l => l.type !== DocumentType.LINK);
- const activeGroups = NumListCast(this.Document.cardSort_visibleSortGroups);
-
- if (activeGroups.length > 0 && this.cardSort === cardSortings.Custom) {
- return regularDocs.filter(doc => {
- // Get the group number for the current index
- const groupNumber = CollectionCardView.getButtonGroup(this.cardSort_customField, doc);
- // Check if the group number is in the active groups
- return groupNumber !== undefined && activeGroups.includes(groupNumber);
- });
- }
-
- // Default return for non-custom cardSort or other cases, filtering out links
- return regularDocs;
- }
+ quizMode = () => {
+ const randomIndex = Math.floor(Math.random() * this.childDocs.length);
+ SelectionManager.DeselectAll();
+ DocumentView.SelectView(DocumentView.getDocumentView(this.childDocs[randomIndex]), false);
+ };
/**
- * Determines the order in which the cards will be rendered depending on the current sort type
+ * Number of rows of cards to be rendered
*/
- @computed get sortedDocs() {
- return this.sort(this.childDocsWithoutLinks, this.cardSort, BoolCast(this.layoutDoc.sortDesc));
+ @computed get numRows() {
+ return Math.ceil(this.sortedDocs.length / this._maxRowCount);
}
@action
@@ -157,8 +175,7 @@ export class CollectionCardView extends CollectionSubView() {
*/
inactiveDocs = () => this.childDocsWithoutLinks.filter(d => !DocumentView.SelectedDocs().includes(d));
- panelWidth = () => this._childDocumentWidth;
- panelHeight = (layout: Doc) => () => (this.panelWidth() * NumCast(layout._height)) / NumCast(layout._width);
+ childPanelWidth = () => NumCast(this.layoutDoc.childPanelWidth, this._props.PanelWidth() / 2);
onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick);
isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this._props.isAnyChildContentActive();
isChildContentActive = () => !!this.isContentActive();
@@ -170,6 +187,8 @@ export class CollectionCardView extends CollectionSubView() {
* @returns
*/
rotate = (amCards: number, index: number) => {
+ if (amCards == 1) return 0;
+
const possRotate = -30 + index * (30 / ((amCards - (amCards % 2)) / 2));
const stepMag = Math.abs(-30 + (amCards / 2 - 1) * (30 / ((amCards - (amCards % 2)) / 2)));
@@ -188,11 +207,12 @@ export class CollectionCardView extends CollectionSubView() {
translateY = (amCards: number, index: number, realIndex: number) => {
const evenOdd = amCards % 2;
const apex = (amCards - evenOdd) / 2;
- const stepMag = 200 / ((amCards - evenOdd) / 2) + Math.abs((apex - index) * 25);
+ const Magnitude = this.childPanelWidth() / 2; // 400
+ const stepMag = Magnitude / 2 / ((amCards - evenOdd) / 2) + Math.abs((apex - index) * 25);
let rowOffset = 0;
if (realIndex > this._maxRowCount - 1) {
- rowOffset = 400 * ((realIndex - (realIndex % this._maxRowCount)) / this._maxRowCount);
+ rowOffset = Magnitude * ((realIndex - (realIndex % this._maxRowCount)) / this._maxRowCount);
}
if (evenOdd === 1 || index < apex - 1) {
return Math.abs(stepMag * (apex - index)) - rowOffset;
@@ -205,27 +225,114 @@ export class CollectionCardView extends CollectionSubView() {
};
/**
- * Translates the selected node to the middle fo the screen
- * @param index
- * @returns
+ * When dragging a card, determines the index the card should be set to if dropped
+ * @param mouseX mouse's x location
+ * @param mouseY mouses' y location
+ * @returns the card's new index
*/
- translateSelected = (index: number): number => {
- // if (this.isSelected(index)) {
- const middleOfPanel = this._props.PanelWidth() / 2;
- const scaledNodeWidth = this.panelWidth() * 1.25;
+ findCardDropIndex = (mouseX: number, mouseY: number) => {
+ const amCardsTotal = this.sortedDocs.length;
+ let index = 0;
+ const cardWidth = amCardsTotal < this._maxRowCount ? this._props.PanelWidth() / amCardsTotal : this._props.PanelWidth() / this._maxRowCount;
+
+ // Calculate the adjusted X position accounting for the initial offset
+ let adjustedX = mouseX;
+
+ const amRows = Math.ceil(amCardsTotal / this._maxRowCount);
+ const rowHeight = this._props.PanelHeight() / amRows;
+ const currRow = Math.floor((mouseY - 100) / rowHeight); //rows start at 0
- // Calculate the position of the node's left edge before scaling
- const nodeLeftEdge = index * this.panelWidth();
- // Find the center of the node after scaling
- const scaledNodeCenter = nodeLeftEdge + scaledNodeWidth / 2;
+ if (adjustedX < 0) {
+ return 0; // Before the first column
+ }
- // Calculate the translation needed to align the scaled node's center with the panel's center
- const translation = middleOfPanel - scaledNodeCenter - scaledNodeWidth - scaledNodeWidth / 4;
+ if (amCardsTotal < this._maxRowCount) {
+ index = Math.floor(adjustedX / cardWidth);
+ } else if (currRow != amRows - 1) {
+ index = Math.floor(adjustedX / cardWidth) + currRow * this._maxRowCount;
+ } else {
+ const rowAmCards = amCardsTotal - currRow * this._maxRowCount;
+ const offset = ((this._maxRowCount - rowAmCards) / 2) * cardWidth;
+ adjustedX = mouseX - offset;
- return translation;
+ index = Math.floor(adjustedX / cardWidth) + currRow * this._maxRowCount;
+ }
+ return index;
};
/**
+ * Checks to see if a card is being dragged and calls the appropriate methods if so
+ * @param e the current pointer event
+ */
+
+ @action
+ onPointerMove = (x: number, y: number) => {
+ this._docDraggedIndex = -1;
+ if (DragManager.docsBeingDragged.length) {
+ const newIndex = this.findCardDropIndex(x, y);
+
+ if (newIndex !== this._docDraggedIndex && newIndex != -1) {
+ this._docDraggedIndex = newIndex;
+ }
+ }
+ };
+
+ /**
+ * Handles external drop of images/PDFs etc from outside Dash.
+ */
+ onExternalDrop = async (e: React.DragEvent): Promise<void> => {
+ super.onExternalDrop(e, {});
+ };
+
+ /**
+ * Resets all the doc dragging vairables once a card is dropped
+ * @param e
+ * @param de drop event
+ * @returns true if a card has been dropped, falls if not
+ */
+ onInternalDrop = undoable(
+ action((e: Event, de: DragManager.DropEvent) => {
+ if (de.complete.docDragData) {
+ const dragIndex = this._docDraggedIndex;
+ const draggedDoc = DragManager.docsBeingDragged[0];
+ if (dragIndex > -1 && draggedDoc) {
+ this._docDraggedIndex = -1;
+ const sorted = this.sortedDocs;
+ const originalIndex = sorted.findIndex(doc => doc === draggedDoc);
+
+ this.Document.cardSort = '';
+ originalIndex !== -1 && sorted.splice(originalIndex, 1);
+ sorted.splice(dragIndex, 0, draggedDoc);
+ if (de.complete.docDragData.removeDocument?.(draggedDoc)) {
+ this.dataDoc[this.fieldKey] = new List<Doc>(sorted);
+ }
+ }
+ e.stopPropagation();
+ return true;
+ }
+ return false;
+ }),
+ ''
+ );
+
+ @computed get sortedDocs() {
+ return this.sort(this.childDocsWithoutLinks, this.cardSort, BoolCast(this.Document.cardSort_isDesc), this._docDraggedIndex);
+ }
+
+ /**
+ * Used to determine how to sort cards based on tags. The lestmost tags are given lower values while cards to the right are
+ * given higher values. Decimals are used to determine placement for cards with multiple tags
+ * @param doc the doc whose value is being determined
+ * @returns its value based on its tags
+ */
+
+ tagValue = (doc: Doc) =>
+ Doc.MyFilterHotKeys.map((key, i) => ({ has: TagItem.docHasTag(doc, StrCast(key.toolType)), i }))
+ .filter(({ has }) => has)
+ .map(({ i }) => i)
+ .join('.');
+
+ /**
* Called in the sortedDocsType method. Compares the cards' value in regards to the desired sort type-- earlier cards are move to the
* front, latter cards to the back
* @param docs
@@ -233,35 +340,43 @@ export class CollectionCardView extends CollectionSubView() {
* @param isDesc
* @returns
*/
- sort = (docs: Doc[], sortType: cardSortings, isDesc: boolean) => {
- if (sortType === cardSortings.None) return docs;
- docs.sort((docA, docB) => {
- const [typeA, typeB] = (() => {
- switch (sortType) {
- case cardSortings.Time:
- return [DateCast(docA.author_date)?.date ?? Date.now(),
- DateCast(docB.author_date)?.date ?? Date.now()];
- case cardSortings.Color:
- return [DashColor(StrCast(docA.backgroundColor)).hsv().toString(), // If docA.type is undefined, use an empty string
- DashColor(StrCast(docB.backgroundColor)).hsv().toString()]; // If docB.type is undefined, use an empty string
- case cardSortings.Custom:
- return [CollectionCardView.getButtonGroup(this.cardSort_customField, docA)??0,
- CollectionCardView.getButtonGroup(this.cardSort_customField, docB)??0];
- default: return [StrCast(docA.type), // If docA.type is undefined, use an empty string
- StrCast(docB.type)]; // If docB.type is undefined, use an empty string
- } // prettier-ignore
- })();
-
- const out = typeA < typeB ? -1 : typeA > typeB ? 1 : 0;
- return isDesc ? -out : out; // Reverse the sort order if descending is true
- });
+ sort = (docs: Doc[], sortType: cardSortings, isDesc: boolean, dragIndex: number) => {
+ sortType &&
+ docs.sort((docA, docB) => {
+ const [typeA, typeB] = (() => {
+ switch (sortType) {
+ case cardSortings.Time:
+ return [DateCast(docA.author_date)?.date ?? Date.now(), DateCast(docB.author_date)?.date ?? Date.now()];
+ case cardSortings.Color: {
+ const d1 = DashColor(StrCast(docA.backgroundColor));
+ const d2 = DashColor(StrCast(docB.backgroundColor));
+ return [d1.hsv().hue(), d2.hsv().hue()];
+ }
+ case cardSortings.Tag:
+ return [this.tagValue(docA) ?? 9999, this.tagValue(docB) ?? 9999];
+ case cardSortings.Chat:
+ return [NumCast(docA.chatIndex) ?? 9999, NumCast(docB.chatIndex) ?? 9999];
+ default:
+ return [StrCast(docA.type), StrCast(docB.type)];
+ }
+ })();
+
+ const out = typeA < typeB ? -1 : typeA > typeB ? 1 : 0;
+ return isDesc ? out : -out;
+ });
+ if (dragIndex != -1) {
+ const draggedDoc = DragManager.docsBeingDragged[0];
+ const originalIndex = docs.findIndex(doc => doc === draggedDoc);
+
+ originalIndex !== -1 && docs.splice(originalIndex, 1);
+ docs.splice(dragIndex, 0, draggedDoc);
+ }
- return docs;
+ return [...docs]; // need to spread docs into a new object list since sort() modifies the incoming list which confuses mobx caching
};
displayDoc = (doc: Doc, screenToLocalTransform: () => Transform) => (
<DocumentView
- // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
ref={action((r: DocumentView) => r?.ContentDiv && this._docRefs.set(doc, r))}
Document={doc}
@@ -273,10 +388,14 @@ export class CollectionCardView extends CollectionSubView() {
LayoutTemplate={this._props.childLayoutTemplate}
LayoutTemplateString={this._props.childLayoutString}
ScreenToLocalTransform={screenToLocalTransform} // makes sure the box wrapper thing is in the right spot
- isContentActive={this.isChildContentActive}
+ isContentActive={emptyFunction}
isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
- PanelWidth={this.panelWidth}
- PanelHeight={this.panelHeight(doc)}
+ PanelWidth={this.childPanelWidth}
+ PanelHeight={() => this._props.PanelHeight() * this.fitContentScale}
+ dontCenter="y" // Don't center it vertically, because the grid it's in is already doing that and we don't want to do it twice.
+ dragAction={(this.Document.childDragAction ?? this._props.childDragAction) as dropActionType}
+ showTags={true}
+ dontHideOnDrag
/>
);
@@ -286,24 +405,24 @@ export class CollectionCardView extends CollectionSubView() {
* @returns
*/
overflowAmCardsCalc = (index: number) => {
- if (this.inactiveDocs().length < this._maxRowCount) {
- return this.inactiveDocs().length;
+ if (this.sortedDocs.length < this._maxRowCount) {
+ return this.sortedDocs.length;
}
// 13 - 3 = 10
- const totalCards = this.inactiveDocs().length;
+ const totalCards = this.sortedDocs.length;
// if 9 or less
- if (index < totalCards - (totalCards % 10)) {
+ if (index < totalCards - (totalCards % this._maxRowCount)) {
return this._maxRowCount;
}
// (3)
- return totalCards % 10;
+ return totalCards % this._maxRowCount;
};
/**
* Determines the index a card is in in a row
* @param realIndex
* @returns
*/
- overflowIndexCalc = (realIndex: number) => realIndex % 10;
+ overflowIndexCalc = (realIndex: number) => realIndex % this._maxRowCount;
/**
* Translates the cards in the second rows and beyond over to the right
* @param realIndex
@@ -311,7 +430,7 @@ export class CollectionCardView extends CollectionSubView() {
* @param calcRowCards
* @returns
*/
- translateOverflowX = (realIndex: number, calcRowCards: number) => (realIndex < this._maxRowCount ? 0 : (10 - calcRowCards) * (this.panelWidth() / 2));
+ translateOverflowX = (realIndex: number, calcRowCards: number) => (realIndex < this._maxRowCount ? 0 : (this._maxRowCount - calcRowCards) * (this.childPanelWidth() / 2));
/**
* Determines how far to translate a card in the y direction depending on its index, whether or not its being hovered, or if it's selected
@@ -323,22 +442,15 @@ export class CollectionCardView extends CollectionSubView() {
* @returns
*/
calculateTranslateY = (isHovered: boolean, isSelected: boolean, realIndex: number, amCards: number, calcRowIndex: number) => {
- if (isSelected) return 50 * this.fitContentScale;
- const trans = isHovered ? this.translateHover(realIndex) : 0;
- return trans + this.translateY(amCards, calcRowIndex, realIndex);
+ const rowHeight = (this._props.PanelHeight() * this.fitContentScale) / this.numRows;
+ const rowIndex = Math.trunc(realIndex / this._maxRowCount);
+ const rowToCenterShift = this.numRows / 2 - rowIndex;
+ if (isSelected) return rowToCenterShift * rowHeight - rowHeight / 2;
+ if (amCards == 1) return 50 * this.fitContentScale;
+ return this.translateY(amCards, calcRowIndex, realIndex);
};
/**
- * Toggles the buttons between on and off when creating custom sort groupings/changing those created by gpt
- * @param childPairIndex
- * @param buttonID
- * @param doc
- */
- toggleButton = undoable((buttonID: number, doc: Doc) => {
- this.cardSort_customField && (doc[this.cardSort_customField] = buttonID);
- }, 'toggle custom button');
-
- /**
* A list of the text content of all the child docs. RTF documents will have just their text and pdf documents will have the first 50 words.
* Image documents are converted to bse64 and gpt generates a description for them. all other documents use their title. This string is
* inputted into the gpt prompt to sort everything together
@@ -355,6 +467,7 @@ export class CollectionCardView extends CollectionSubView() {
};
const docTextPromises = this.childDocsWithoutLinks.map(async doc => {
const docText = (await docToText(doc)) ?? '';
+ doc.gptInputText = docText;
this._textToDoc.set(docText.replace(/\n/g, ' ').trim(), doc);
return `======${docText.replace(/\n/g, ' ').trim()}======`;
});
@@ -377,78 +490,107 @@ export class CollectionCardView extends CollectionSubView() {
image[DocData].description = response.trim();
return response; // Return the response from gptImageLabel
} catch (error) {
- console.log('bad things have happened');
+ console.log(error);
}
return '';
};
/**
- * Converts the gpt output into a hashmap that can be used for sorting. lists are seperated by ==== while elements within the list are seperated by ~~~~~~
+ * Processes gpt's output depending on the type of question the user asked. Converts gpt's string output to
+ * usable code
* @param gptOutput
*/
- processGptOutput = (gptOutput: string) => {
+ @action
+ processGptOutput = undoable((gptOutput: string, questionType: string, tag?: string) => {
// Split the string into individual list items
const listItems = gptOutput.split('======').filter(item => item.trim() !== '');
+
+ if (questionType === '2' || questionType === '4') {
+ this.childDocs.forEach(d => {
+ d.chatFilter = false;
+ });
+ }
+
+ if (questionType === '6') {
+ this.Document.cardSort = 'chat';
+ }
+
listItems.forEach((item, index) => {
- // Split the item by '~~~~~~' to get all descriptors
- const parts = item.split('~~~~~~').map(part => part.trim());
-
- parts.forEach(part => {
- // Find the corresponding Doc in the textToDoc map
- const doc = this._textToDoc.get(part);
- if (doc) {
- doc.chat = index;
+ const normalizedItem = item.trim();
+ // find the corresponding Doc in the textToDoc map
+ const doc = this._textToDoc.get(normalizedItem);
+
+ if (doc) {
+ switch (questionType) {
+ case '6':
+ doc.chatIndex = index;
+ break;
+ case '1': {
+ const allHotKeys = Doc.MyFilterHotKeys;
+
+ let myTag = '';
+
+ if (tag) {
+ for (let i = 0; i < allHotKeys.length; i++) {
+ // bcz: CHECK THIS CODE OUT -- SOMETHING CHANGED
+ const keyTag = StrCast(allHotKeys[i].toolType);
+ if (tag.includes(keyTag)) {
+ myTag = keyTag;
+ break;
+ }
+ }
+
+ if (myTag != '') {
+ doc[myTag] = true;
+ }
+ }
+ break;
+ }
+ case '2':
+ case '4':
+ doc.chatFilter = true;
+ Doc.setDocFilter(DocCast(this.Document.embedContainer), 'chatFilter', true, 'match');
+ break;
}
- });
+ } else {
+ console.warn(`No matching document found for item: ${normalizedItem}`);
+ }
});
- };
+ }, '');
+
/**
* Opens up the chat popup and starts the process for smart sorting.
*/
openChatPopup = async () => {
GPTPopup.Instance.setVisible(true);
- GPTPopup.Instance.setMode(GPTPopupMode.SORT);
- const sortDesc = await this.childPairStringList(); // Await the promise to get the string result
+ GPTPopup.Instance.setMode(GPTPopupMode.CARD);
GPTPopup.Instance.setCardsDoneLoading(true); // Set dataDoneLoading to true after data is loaded
- GPTPopup.Instance.setSortDesc(sortDesc.join());
- GPTPopup.Instance.onSortComplete = (sortResult: string) => this.processGptOutput(sortResult);
+ await this.childPairStringListAndUpdateSortDesc();
};
/**
- * Renders the buttons to customize sorting depending on which group the card belongs to and the amount of total groups
- * @param childPairIndex
- * @param doc
- * @returns
- */
- renderButtons = (doc: Doc, cardSort: cardSortings) => {
- if (cardSort !== cardSortings.Custom) return '';
- const amButtons = Math.max(4, this.childDocs?.reduce((set, d) => this.cardSort_customField && set.add(NumCast(d[this.cardSort_customField])), new Set<number>()).size ?? 0);
- const activeButtonIndex = CollectionCardView.getButtonGroup(this.cardSort_customField, doc);
- const totalWidth = amButtons * 35 + amButtons * 2 * 5 + 6;
- return (
- <div className="card-button-container" style={{ width: `${totalWidth}px` }}>
- {numberRange(amButtons).map(i => (
- <button
- key={i}
- type="button"
- style={{ backgroundColor: activeButtonIndex === i ? '#4476f7' : '#323232' }} //
- onClick={() => this.toggleButton(i, doc)}
- />
- ))}
- </div>
- );
- };
- /**
* Actually renders all the cards
*/
- renderCards = () => {
+ @computed get renderCards() {
+ const sortedDocs = this.sortedDocs;
const anySelected = this.childDocs.some(doc => DocumentView.SelectedDocs().includes(doc));
+ const isEmpty = this.childDocsWithoutLinks.length === 0;
+
+ if (isEmpty) {
+ return (
+ <span className="no-card-span" style={{ width: ` ${this._props.PanelWidth()}px`, height: ` ${this._props.PanelHeight()}px` }}>
+ Sorry ! There are no cards in this group
+ </span>
+ );
+ }
+
// Map sorted documents to their rendered components
- return this.sortedDocs.map((doc, index) => {
- const realIndex = this.sortedDocs.filter(sortDoc => !DocumentView.SelectedDocs().includes(sortDoc)).indexOf(doc);
+ return sortedDocs.map((doc, index) => {
+ const realIndex = sortedDocs.indexOf(doc);
const calcRowIndex = this.overflowIndexCalc(realIndex);
const amCards = this.overflowAmCardsCalc(realIndex);
- const isSelected = DocumentView.SelectedDocs().includes(doc);
+ const view = DocumentView.getDocumentView(doc, this.DocumentView?.());
+ const isSelected = view?.ComponentView?.isAnyChildContentActive?.() || view?.IsSelected ? true : false;
const childScreenToLocal = () => {
this._forceChildXf;
@@ -459,41 +601,56 @@ export class CollectionCardView extends CollectionSubView() {
.scale(1 / scale).rotate(!isSelected ? -this.rotate(amCards, calcRowIndex) : 0); // prettier-ignore
};
+ const translateIfSelected = () => {
+ const indexInRow = index % this._maxRowCount;
+ const rowIndex = Math.trunc(index / this._maxRowCount);
+ const rowCenterIndex = Math.min(this._maxRowCount, sortedDocs.length - rowIndex * this._maxRowCount) / 2;
+ return (rowCenterIndex - indexInRow) * 100 - 50;
+ };
+ const aspect = NumCast(doc.height) / NumCast(doc.width, 1);
+ const vscale = Math.min((this._props.PanelHeight() * 0.95 * this.fitContentScale) / (aspect * this.childPanelWidth()),
+ (this._props.PanelHeight() - 80) / (aspect * (this._props.PanelWidth() / 10))); // prettier-ignore
+ const hscale = Math.min(this.sortedDocs.length, this._maxRowCount) / 2; // bcz: hack - the grid is divided evenly into maxRowCount cells, so the max scaling would be maxRowCount -- but making things that wide is ugly, so cap it off at half the window size
return (
<div
key={doc[Id]}
className={`card-item${isSelected ? '-active' : anySelected ? '-inactive' : ''}`}
onPointerUp={() => {
+ if (DocumentView.SelectedDocs().includes(doc)) return;
// this turns off documentDecorations during a transition, then turns them back on afterward.
- SnappingManager.SetIsResizing(this.Document[Id]);
+ SnappingManager.SetIsResizing(doc[Id]);
setTimeout(
action(() => {
SnappingManager.SetIsResizing(undefined);
this._forceChildXf = !this._forceChildXf;
}),
- 700
+ 900
);
}}
style={{
- width: this.panelWidth(),
- height: 'max-content', // this.panelHeight(childPair.layout)(),
+ width: this.childPanelWidth(),
+ height: 'max-content',
transform: `translateY(${this.calculateTranslateY(this._hoveredNodeIndex === index, isSelected, realIndex, amCards, calcRowIndex)}px)
- translateX(${isSelected ? this.translateSelected(calcRowIndex) : this.translateOverflowX(realIndex, amCards)}px)
+ translateX(calc(${isSelected ? translateIfSelected() : 0}% + ${this.translateOverflowX(realIndex, amCards)}px))
rotate(${!isSelected ? this.rotate(amCards, calcRowIndex) : 0}deg)
- scale(${isSelected ? 1.25 : 1})`,
- }}
+ scale(${isSelected ? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.05 : 1})`,
+ }} // prettier-ignore
onMouseEnter={() => this.setHoveredNodeIndex(index)}>
{this.displayDoc(doc, childScreenToLocal)}
- {this.renderButtons(doc, this.cardSort)}
</div>
);
});
- };
+ }
+
render() {
+ const isEmpty = this.childDocsWithoutLinks.length === 0;
+
return (
<div
className="collectionCardView-outer"
- ref={this.createDashEventsTarget}
+ ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)}
+ onPointerMove={e => this.onPointerMove(e.clientX, e.clientY)}
+ onDrop={this.onExternalDrop.bind(this)}
style={{
background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string,
color: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string,
@@ -501,11 +658,12 @@ export class CollectionCardView extends CollectionSubView() {
<div
className="card-wrapper"
style={{
- transform: ` scale(${1 / this.fitContentScale}) translateX(${this.translateWrapperX}px)`,
- height: `${100 * this.fitContentScale}%`,
+ ...(!isEmpty && { transform: `scale(${1 / this.fitContentScale})` }),
+ ...(!isEmpty && { height: `${100 * this.fitContentScale}%` }),
+ gridAutoRows: `${100 / this.numRows}%`,
}}
onMouseLeave={() => this.setHoveredNodeIndex(-1)}>
- {this.renderCards()}
+ {this.renderCards}
</div>
</div>
);
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index 0473bb163..4951590dc 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -77,6 +77,7 @@ export class CollectionCarousel3DView extends CollectionSubView() {
NativeWidth={returnZero}
NativeHeight={returnZero}
fitWidth={this._props.childLayoutFitWidth}
+ containerViewPath={this.childContainerViewPath}
onDoubleClickScript={this.onChildDoubleClick}
renderDepth={this._props.renderDepth + 1}
LayoutTemplate={this._props.childLayoutTemplate}
diff --git a/src/client/views/collections/CollectionCarouselView.scss b/src/client/views/collections/CollectionCarouselView.scss
index f115bb40a..01b20d6d3 100644
--- a/src/client/views/collections/CollectionCarouselView.scss
+++ b/src/client/views/collections/CollectionCarouselView.scss
@@ -12,6 +12,21 @@
user-select: none;
}
}
+.collectionCarouselView-addFlashcards {
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+ z-index: -1;
+ pointer-events: none;
+}
+.collectionCarouselView-recentlyMissed {
+ color: red;
+ z-index: 999;
+ position: relative;
+ left: 10px;
+ top: 10px;
+ pointer-events: none;
+}
.carouselView-back,
.carouselView-fwd,
.carouselView-star,
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 264a34680..9741c45fe 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -1,16 +1,15 @@
-/* eslint-disable react/jsx-props-no-spreading */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { computed, makeObservable } from 'mobx';
+import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { StopEvent, returnFalse, returnOne, returnTrue, returnZero } from '../../../ClientUtils';
-import { emptyFunction } from '../../../Utils';
-import { Doc, Opt } from '../../../fields/Doc';
-import { Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
+import { StopEvent, returnOne, returnZero } from '../../../ClientUtils';
+import { Doc, DocListCast, Opt } from '../../../fields/Doc';
+import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { DocumentType } from '../../documents/DocumentTypes';
import { DragManager } from '../../util/DragManager';
import { ContextMenu } from '../ContextMenu';
import { StyleProp } from '../StyleProp';
+import { TagItem } from '../TagsView';
import { DocumentView } from '../nodes/DocumentView';
import { FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
@@ -30,15 +29,36 @@ enum practiceVal {
export class CollectionCarouselView extends CollectionSubView() {
private _dropDisposer?: DragManager.DragDropDisposer;
get practiceField() { return this.fieldKey + "_practice"; } // prettier-ignore
- get starField() { return this.fieldKey + "_star"; } // prettier-ignore
+ get starField() { return "#star"; } // prettier-ignore
+
+ _fadeTimer: NodeJS.Timeout | undefined;
+ _resetter: IReactionDisposer | undefined;
constructor(props: SubCollectionViewProps) {
super(props);
makeObservable(this);
}
+ @observable _last_index = this.carouselIndex;
+ @observable _last_opacity = 1;
+
+ componentDidMount() {
+ this._resetter = reaction(
+ // automatically reset practice fields when all cards have been marked as correct
+ () => this.carouselItems.length,
+ itemsCount => {
+ if (this.layoutDoc.filterOp === cardMode.PRACTICE && !itemsCount) {
+ this.layoutDoc.filterOp = undefined; // if all of the cards are correct, show all cards and exit practice mode
+ this.carouselItems.forEach(item => { // reset all the practice values
+ item[this.practiceField] = undefined;
+ });
+ }
+ } // prettier-ignore
+ );
+ }
componentWillUnmount() {
this._dropDisposer?.();
+ this._resetter?.();
}
protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
@@ -48,43 +68,24 @@ export class CollectionCarouselView extends CollectionSubView() {
}
};
+ @computed get marginX() { return NumCast(this.layoutDoc.caption_xMargin, 50); } // prettier-ignore
+ @computed get carouselIndex() { return NumCast(this.layoutDoc._carousel_index) % this.carouselItems.length; } // prettier-ignore
@computed get carouselItems() {
- return this.childLayoutPairs.filter(pair => pair.layout.type !== DocumentType.LINK);
- }
- @computed get marginX() {
- return NumCast(this.layoutDoc.caption_xMargin, 50);
+ return DocListCast(this.childDocList)
+ .filter(doc => doc.type !== DocumentType.LINK)
+ .filter(doc => {
+ switch (StrCast(this.layoutDoc.filterOp)) {
+ case cardMode.STAR: return !!doc[this.starField]; // show only cards that are starred
+ case cardMode.PRACTICE: return doc[this.practiceField] !== practiceVal.CORRECT;// show only cards that aren't marked as correct
+ default: return true;
+ } // prettier-ignore
+ });
}
- move = (dir: number) => {
- const moveToCardWithField = (match: (doc: Doc) => boolean): boolean => {
- let startInd = (NumCast(this.layoutDoc._carousel_index) + dir) % this.carouselItems.length;
- while (!match(this.carouselItems?.[startInd].layout) && (startInd + dir + this.carouselItems.length) % this.carouselItems.length !== this.layoutDoc._carousel_index) {
- startInd = (startInd + dir + this.carouselItems.length) % this.carouselItems.length;
- }
- if (match(this.carouselItems?.[startInd].layout)) {
- this.layoutDoc._carousel_index = startInd;
- return true;
- }
- return match(this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout);
- };
- switch (StrCast(this.layoutDoc.filterOp)) {
- case cardMode.STAR: // go to a flashcard that is starred, skip the ones that aren't
- if (!moveToCardWithField((doc: Doc) => !!doc[this.starField])) {
- this.layoutDoc.filterOp = undefined; // if there aren't any starred, show all cards
- }
- break;
- case cardMode.PRACTICE: // go to a new index that is missed, skip the ones that are correct
- if (!moveToCardWithField((doc: Doc) => doc[this.practiceField] !== practiceVal.CORRECT)) {
- this.layoutDoc.filterOp = undefined; // if all of the cards are correct, show all cards and exit practice mode
-
- this.carouselItems.forEach(item => { // reset all the practice values
- item.layout[this.practiceField] = undefined;
- });
- }
- break;
- default: moveToCardWithField(returnTrue);
- } // prettier-ignore
- };
+ move = action((dir: number) => {
+ this._last_index = this.carouselIndex;
+ this.layoutDoc._carousel_index = (this.carouselIndex + dir + this.carouselItems.length) % this.carouselItems.length;
+ });
/**
* Goes to the next Doc in the stack subject to the currently selected filter option.
@@ -107,8 +108,11 @@ export class CollectionCarouselView extends CollectionSubView() {
*/
star = (e: React.MouseEvent) => {
e.stopPropagation();
- const curDoc = this.carouselItems[NumCast(this.layoutDoc._carousel_index)];
- curDoc.layout[this.starField] = curDoc.layout[this.starField] ? undefined : true;
+ const curDoc = this.carouselItems[this.carouselIndex];
+ if (curDoc) {
+ if (TagItem.docHasTag(curDoc, this.starField)) TagItem.removeTagFromDoc(curDoc, this.starField);
+ else TagItem.addTagToDoc(curDoc, this.starField);
+ }
};
/*
@@ -116,8 +120,8 @@ export class CollectionCarouselView extends CollectionSubView() {
*/
setPracticeVal = (e: React.MouseEvent, val: string) => {
e.stopPropagation();
- const curDoc = this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)];
- curDoc.layout[this.practiceField] = val;
+ const curDoc = this.carouselItems[this.carouselIndex];
+ curDoc && (curDoc[this.practiceField] = val);
this.advance(e);
};
@@ -132,7 +136,6 @@ export class CollectionCarouselView extends CollectionSubView() {
captionWidth = () => this._props.PanelWidth() - 2 * this.marginX;
specificMenu = (): void => {
const cm = ContextMenu.Instance;
-
const revealOptions = cm.findByDescription('Filter Flashcards');
const revealItems = revealOptions?.subitems ?? [];
revealItems.push({description: 'All', event: () => {this.layoutDoc.filterOp = undefined;}, icon: 'layer-group',}); // prettier-ignore
@@ -142,34 +145,78 @@ export class CollectionCarouselView extends CollectionSubView() {
!revealOptions && cm.addItem({ description: 'Filter Flashcards', addDivider: false, noexpand: true, subitems: revealItems, icon: 'layer-group' });
};
childFitWidth = (doc: Doc) => Cast(this.Document.childLayoutFitWidth, 'boolean', this._props.childLayoutFitWidth?.(doc) ?? Cast(doc.layout_fitWidth, 'boolean', null));
+
+ isChildContentActive = () =>
+ this._props.isContentActive?.() === false
+ ? false
+ : this._props.isDocumentActive?.() && (this._props.childDocumentsActive?.() || BoolCast(this.Document.childDocumentsActive))
+ ? true
+ : this._props.childDocumentsActive?.() === false || this.Document.childDocumentsActive === false
+ ? false
+ : undefined;
+
+ renderDoc = (doc: Doc, showCaptions: boolean, overlayFunc?: (r: DocumentView | null) => void) => {
+ return (
+ <DocumentView
+ {...this._props}
+ ref={overlayFunc}
+ Document={doc}
+ NativeWidth={returnZero}
+ NativeHeight={returnZero}
+ fitWidth={undefined}
+ containerViewPath={this.childContainerViewPath}
+ setContentViewBox={undefined}
+ onDoubleClickScript={this.onContentDoubleClick}
+ onClickScript={this.onContentClick}
+ isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive}
+ isContentActive={this.isChildContentActive}
+ hideCaptions={showCaptions}
+ renderDepth={this._props.renderDepth + 1}
+ LayoutTemplate={this._props.childLayoutTemplate}
+ LayoutTemplateString={this._props.childLayoutString}
+ TemplateDataDocument={DocCast(Doc.Layout(doc).resolvedDataDoc)}
+ PanelHeight={this.panelHeight}
+ />
+ );
+ };
+ /**
+ * Display an overlay of the previous card that crossfades to the next card
+ */
+ @computed get overlay() {
+ const fadeTime = 500;
+ const lastDoc = this.carouselItems?.[this._last_index];
+ return !lastDoc || this.carouselIndex === this._last_index ? null : (
+ <div className="collectionCarouselView-image" style={{ opacity: this._last_opacity, position: 'absolute', top: 0, left: 0, transition: `opacity ${fadeTime}ms` }}>
+ {this.renderDoc(
+ lastDoc,
+ false, // hide captions if the carousel is configured to show the captions
+ action((r: DocumentView | null) => {
+ if (r) {
+ this._fadeTimer && clearTimeout(this._fadeTimer);
+ this._last_opacity = 0;
+ this._fadeTimer = setTimeout(
+ action(() => {
+ this._last_index = -1;
+ this._last_opacity = 1;
+ }),
+ fadeTime
+ );
+ }
+ })
+ )}
+ </div>
+ );
+ }
@computed get content() {
- const index = NumCast(this.layoutDoc._carousel_index);
+ const index = this.carouselIndex;
const curDoc = this.carouselItems?.[index];
const captionProps = { ...this._props, NativeScaling: returnOne, PanelWidth: this.captionWidth, fieldKey: 'caption', setHeight: undefined, setContentView: undefined };
const carouselShowsCaptions = StrCast(this.layoutDoc._layout_showCaption);
- return !(curDoc?.layout instanceof Doc) ? null : (
+ return !curDoc ? null : (
<>
<div className="collectionCarouselView-image" key="image">
- <DocumentView
- {...this._props}
- // NativeWidth={returnZero}
- // NativeHeight={returnZero}
- fitWidth={returnTrue}
- setContentViewBox={undefined}
- containerViewPath={this._props.docViewPath}
- onDoubleClickScript={this.onContentDoubleClick}
- onClickScript={this.onContentClick}
- isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive}
- isContentActive={(this._props.childContentsActive ?? this._props.isContentActive() === false) ? returnFalse : emptyFunction}
- hideCaptions={!!carouselShowsCaptions} // hide captions if the carousel is configured to show the captions
- renderDepth={this._props.renderDepth + 1}
- LayoutTemplate={this._props.childLayoutTemplate}
- LayoutTemplateString={this._props.childLayoutString}
- Document={curDoc.layout}
- TemplateDataDocument={DocCast(curDoc.layout.resolvedDataDoc)}
- PanelHeight={this.panelHeight}
- PanelWidth={this._props.PanelWidth}
- />
+ {this.renderDoc(curDoc, !!carouselShowsCaptions)}
+ {this.overlay}
</div>
{!carouselShowsCaptions ? null : (
<div
@@ -182,14 +229,14 @@ export class CollectionCarouselView extends CollectionSubView() {
marginLeft: this.marginX,
width: `calc(100% - ${this.marginX * 2}px)`,
}}>
- <FormattedTextBox key={index} {...captionProps} fieldKey={carouselShowsCaptions} styleProvider={this.captionStyleProvider} Document={curDoc.layout} TemplateDataDocument={undefined} />
+ <FormattedTextBox key={index} xPadding={10} yPadding={10} {...captionProps} fieldKey={carouselShowsCaptions} styleProvider={this.captionStyleProvider} Document={curDoc} TemplateDataDocument={undefined} />
</div>
)}
</>
);
}
@computed get buttons() {
- if (!this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)]) return null;
+ if (!this.carouselItems?.[this.carouselIndex]) return null;
return (
<>
<div key="back" className="carouselView-back" onClick={this.goback}>
@@ -199,7 +246,7 @@ export class CollectionCarouselView extends CollectionSubView() {
<FontAwesomeIcon icon="chevron-right" size="2x" />
</div>
<div key="star" className="carouselView-star" onClick={this.star}>
- <FontAwesomeIcon icon="star" color={this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout[this.starField] ? 'yellow' : 'gray'} size="1x" />
+ <FontAwesomeIcon icon="star" color={TagItem.docHasTag(this.carouselItems?.[this.carouselIndex], this.starField) ? 'yellow' : 'gray'} size="1x" />
</div>
<div key="remove" className="carouselView-remove" onClick={e => this.setPracticeVal(e, practiceVal.MISSED)} style={{ visibility: this.layoutDoc.filterOp === cardMode.PRACTICE ? 'visible' : 'hidden' }}>
<FontAwesomeIcon icon="xmark" color="red" size="1x" />
@@ -211,6 +258,24 @@ export class CollectionCarouselView extends CollectionSubView() {
);
}
+ /**
+ * Prompts user to add more flashcaards if they are in practice mode but there are no flashcards
+ */
+ renderAddFlashcards = () => <p
+ className="collectionCarouselView-addFlashcards"
+ style={{display: !this.carouselItems?.[this.carouselIndex] && this.layoutDoc.filterOp === cardMode.PRACTICE ? 'flex' : 'none'}}>
+ Add flashcards!
+ </p> // prettier-ignore
+
+ /**
+ * Displays message that a flashcard was recently missed if it had previously been marked as wrong.
+ * */
+ renderRecentlyMissed = () => <p
+ className="collectionCarouselView-recentlyMissed"
+ style={{display: this.carouselItems?.[this.carouselIndex]?.[this.practiceField] === practiceVal.MISSED ? 'block' : 'none'}}>
+ Recently missed!
+ </p> // prettier-ignore
+
render() {
return (
<div
@@ -222,29 +287,8 @@ export class CollectionCarouselView extends CollectionSubView() {
color: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string,
}}>
{this.content}
- {/* Displays a message to the user to add more flashcards if they are in practice mode and no flashcards are there. */}
- <p
- style={{
- display: !this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)] && this.layoutDoc.filterOp === cardMode.PRACTICE ? 'flex' : 'none',
- justifyContent: 'center',
- alignItems: 'center',
- height: '100%',
- zIndex: '-1',
- }}>
- Add flashcards!
- </p>
- {/* Displays a message to the user that a flashcard was recently missed if they had previously gotten it wrong. */}
- <p
- style={{
- color: 'red',
- zIndex: '999',
- position: 'relative',
- left: '10px',
- top: '10px',
- display: this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)] ? (this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout[this.practiceField] === practiceVal.MISSED ? 'block' : 'none') : 'none',
- }}>
- Recently missed!
- </p>
+ {this.renderAddFlashcards()}
+ {this.renderRecentlyMissed()}
{this.Document._chromeHidden ? null : this.buttons}
</div>
);
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index e0aa79c7b..028133a6e 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -31,6 +31,7 @@ import { ScriptingRepl } from '../ScriptingRepl';
import { UndoStack } from '../UndoStack';
import './CollectionDockingView.scss';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
+import { TabHTMLElement } from './TabDocView';
@observer
export class CollectionDockingView extends CollectionSubView() {
@@ -544,7 +545,7 @@ export class CollectionDockingView extends CollectionSubView() {
tabCreated = (tab: { contentItem: { element: HTMLElement[] } }) => {
this.tabMap.add(tab);
// InitTab is added to the tab's HTMLElement in TabDocView
- const tabdocviewContent = tab.contentItem.element[0]?.firstChild?.firstChild as unknown as { InitTab?: (tab: object) => void };
+ const tabdocviewContent = tab.contentItem.element[0]?.firstChild?.firstChild as unknown as TabHTMLElement;
tabdocviewContent?.InitTab?.(tab); // have to explicitly initialize tabs that reuse contents from previous tabs (ie, when dragging a tab around a new tab is created for the old content)
};
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index e1f0a3e41..ac8e37358 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -653,7 +653,6 @@ export class CollectionNoteTakingView extends CollectionSubView() {
const sections = Array.from(this.Sections.entries());
return sections.reduce((list, sec, i) => {
list.push(this.sectionNoteTaking(sec[0], sec[1]));
- // eslint-disable-next-line react/no-array-index-key
i !== sections.length - 1 && list.push(<CollectionNoteTakingViewDivider key={`divider${i}`} isContentActive={this.isContentActive} index={i} setColumnStartXCoords={this.setColumnStartXCoords} xMargin={this.xMargin} />);
return list;
}, [] as JSX.Element[]);
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 6225cc52a..6400a0a8e 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -54,11 +54,8 @@
}
.collectionStackingViewFieldColumn {
- height: max-content;
- }
-
- .collectionStackingViewFieldColumnDragging {
- height: 100%;
+ display: flex;
+ flex-direction: column;
}
.collectionSchemaView-previewDoc {
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 6402ef16c..1ac0b6d70 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable react/jsx-props-no-spreading */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import * as CSS from 'csstype';
import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx';
@@ -35,6 +34,7 @@ import { CollectionMasonryViewFieldRow } from './CollectionMasonryViewFieldRow';
import './CollectionStackingView.scss';
import { CollectionStackingViewFieldColumn } from './CollectionStackingViewFieldColumn';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
+import { computedFn } from 'mobx-utils';
export type collectionStackingViewProps = {
sortFunc?: (a: Doc, b: Doc) => number;
@@ -127,6 +127,9 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}
}
+ columnWidthFn = () => this.columnWidth;
+ columnDocHeightFn = (doc: Doc) => () => (this.isStackingView ? this.getDocHeight(doc)() : Math.min(this.getDocHeight(doc)(), this._props.PanelHeight()));
+
// TODO: plj - these are the children
children = (docs: Doc[]) => {
// TODO: can somebody explain me to what exactly TraceMobX is?
@@ -140,17 +143,14 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
})
);
return docs.map((d, i) => {
- const height = () => this.getDocHeight(d);
- const width = () => this.getDocWidth(d);
- const trans = () => this.getDocTransition(d);
// assuming we need to get rowSpan because we might be dealing with many columns. Grid gap makes sense if multiple columns
- const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap);
+ const rowSpan = Math.ceil((this.getDocHeight(d)() + this.gridGap) / this.gridGap);
// just getting the style
- const style = this.isStackingView ? { margin: this.Document._stacking_alignCenter ? 'auto' : undefined, transition: trans(), width: width(), marginTop: i ? this.gridGap : 0, height: height() } : { gridRowEnd: `span ${rowSpan}` };
+ const style = this.isStackingView ? { margin: undefined, transition: this.getDocTransition(d)(), width: this.columnWidth, marginTop: i ? this.gridGap : 0, height: this.getDocHeight(d)() } : { gridRowEnd: `span ${rowSpan}` };
// So we're choosing whether we're going to render a column or a masonry doc
return (
<div className={`collectionStackingView-${this.isStackingView ? 'columnDoc' : 'masonryDoc'}`} key={d[Id]} style={style}>
- {this.getDisplayDoc(d, width, trans, i)}
+ {this.getDisplayDoc(d, this.getDocTransition(d), i)}
</div>
);
});
@@ -311,26 +311,23 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
: this._props.childDocumentsActive?.() === false || this.Document.childDocumentsActive === false
? false
: undefined;
+
isChildButtonContentActive = () => (this._props.childDocumentsActive?.() === false || this.Document.childDocumentsActive === false ? false : undefined);
@observable docRefs = new ObservableMap<Doc, DocumentView>();
childFitWidth = (doc: Doc) => Cast(this.Document.childLayoutFitWidth, 'boolean', this._props.childLayoutFitWidth?.(doc) ?? Cast(doc.layout_fitWidth, 'boolean', null));
// this is what renders the document that you see on the screen
// called in Children: this actually adds a document to our children list
- getDisplayDoc(doc: Doc, width: () => number, trans: () => string, count: number) {
+ getDisplayDoc(doc: Doc, trans: () => string, count: number) {
const dataDoc = doc.isTemplateDoc || doc.isTemplateForField ? this._props.TemplateDataDocument : undefined;
- const height = () => this.getDocHeight(doc);
- const panelHeight = () => (this.isStackingView ? height() : Math.min(height(), this._props.PanelHeight()));
- const panelWidth = () => this.columnWidth;
- const stackedDocTransform = () => this.getDocTransform(doc);
- this._docXfs.push({ stackedDocTransform, width, height });
+ this._docXfs.push({ stackedDocTransform: this.getDocTransform(doc), width: this.getDocWidth(doc), height: this.getDocHeight(doc) });
return count > this._renderCount ? null : (
<DocumentView
ref={action((r: DocumentView) => r?.ContentDiv && this.docRefs.set(doc, r))}
Document={doc}
TemplateDataDocument={dataDoc}
renderDepth={this._props.renderDepth + 1}
- PanelWidth={panelWidth}
- PanelHeight={panelHeight}
+ PanelWidth={this.columnWidthFn}
+ PanelHeight={this.columnDocHeightFn(doc)}
pointerEvents={this.DocumentView?.()._props.onClickScript?.() ? returnNone : undefined} // if the stack has an onClick, then we don't want the contents to be interactive (see CollectionPileView)
styleProvider={this.styleProvider}
containerViewPath={this.childContainerViewPath}
@@ -341,16 +338,16 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
isDocumentActive={this.isContentActive}
LayoutTemplate={this._props.childLayoutTemplate}
LayoutTemplateString={this._props.childLayoutString}
- NativeWidth={this._props.childIgnoreNativeSize ? returnZero : this._props.childLayoutFitWidth?.(doc) || (this.childFitWidth(doc) && !Doc.NativeWidth(doc)) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
- NativeHeight={this._props.childIgnoreNativeSize ? returnZero : this._props.childLayoutFitWidth?.(doc) || (this.childFitWidth(doc) && !Doc.NativeHeight(doc)) ? height : undefined}
- dontCenter={this._props.childIgnoreNativeSize ? 'xy' : (StrCast(this.layoutDoc.layout_dontCenter) as 'x' | 'y' | 'xy')}
+ NativeWidth={this._props.childIgnoreNativeSize ? returnZero : this._props.childLayoutFitWidth?.(doc) || (this.childFitWidth(doc) && !Doc.NativeWidth(doc)) ? this.getDocWidth(doc) : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
+ NativeHeight={this._props.childIgnoreNativeSize ? returnZero : this._props.childLayoutFitWidth?.(doc) || (this.childFitWidth(doc) && !Doc.NativeHeight(doc)) ? this.getDocHeight(doc) : undefined}
+ dontCenter={this.dontCenter}
dontRegisterView={BoolCast(this.layoutDoc.childDontRegisterViews, this._props.dontRegisterView)} // used to be true if DataDoc existed, but template textboxes won't layout_autoHeight resize if dontRegisterView is set, but they need to.
rootSelected={this.rootSelected}
showTitle={this._props.childlayout_showTitle}
dragAction={(this.layoutDoc.childDragAction ?? this._props.childDragAction) as dropActionType}
onClickScript={this.onChildClickHandler}
onDoubleClickScript={this.onChildDoubleClickHandler}
- ScreenToLocalTransform={stackedDocTransform}
+ ScreenToLocalTransform={this.getDocTransform(doc)}
focus={this.focusDocument}
childFilters={this.childDocFilters}
hideDecorationTitle={this._props.childHideDecorationTitle}
@@ -371,15 +368,18 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
);
}
- getDocTransform(doc: Doc) {
+ getDocTransform = computedFn((doc: Doc) => () => {
+ // these must be referenced for document decorations to update when the text box container is scrolled
+ this._scroll;
+ this._props.ScreenToLocalTransform();
+
const dref = this.docRefs.get(doc);
- this._scroll; // must be referenced for document decorations to update when the text box container is scrolled
const { translateX, translateY, scale } = ClientUtils.GetScreenTransform(dref?.ContentDiv);
return new Transform(-translateX + (dref?.centeringX || 0) * scale,
-translateY + (dref?.centeringY || 0) * scale, 1)
.scale(1 / scale); // prettier-ignore
- }
- getDocWidth(d?: Doc) {
+ });
+ getDocWidth = computedFn((d?: Doc) => () => {
if (!d) return 0;
const childLayoutDoc = Doc.Layout(d, this._props.childLayoutTemplate?.());
const maxWidth = this.columnWidth / this.numGroupColumns;
@@ -387,12 +387,9 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
return Math.min(NumCast(d._width), maxWidth);
}
return maxWidth;
- }
- getDocTransition(d?: Doc) {
- if (!d) return '';
- return StrCast(d.dataTransition);
- }
- getDocHeight(d?: Doc) {
+ });
+ getDocTransition = computedFn((d?: Doc) => () => StrCast(d?.dataTransition));
+ getDocHeight = computedFn((d?: Doc) => () => {
if (!d || d.hidden) return 0;
const childLayoutDoc = Doc.Layout(d, this._props.childLayoutTemplate?.());
const childDataDoc = !d.isTemplateDoc && !d.isTemplateForField ? undefined : this._props.TemplateDataDocument;
@@ -401,13 +398,13 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!this.childFitWidth(childLayoutDoc) ? NumCast(d._height) : 0);
if (nw && nh) {
const colWid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
- const docWid = this.layoutDoc._columnsFill ? colWid : Math.min(this.getDocWidth(d), colWid);
+ const docWid = this.layoutDoc._columnsFill ? colWid : Math.min(this.getDocWidth(d)(), colWid);
return Math.min(maxHeight, (docWid * nh) / nw);
}
const childHeight = NumCast(childLayoutDoc._height);
const panelHeight = this.childFitWidth(childLayoutDoc) ? Number.MAX_SAFE_INTEGER : this._props.PanelHeight() - 2 * this.yMargin;
return Math.min(childHeight, maxHeight, panelHeight);
- }
+ });
// This following three functions must be from the view Mehek showed
columnDividerDown = (e: React.PointerEvent) => {
@@ -531,6 +528,9 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}
});
};
+ @computed get dontCenter() {
+ return this._props.dontCenter ?? (this._props.childIgnoreNativeSize ? 'xy' : (StrCast(this.layoutDoc.layout_dontCenter) as 'x' | 'y' | 'xy'));
+ }
headings = () => Array.from(this.Sections);
// what a section looks like if we're in stacking view
sectionStacking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
@@ -539,7 +539,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
if (this.pivotField) {
const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]);
if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) {
- // eslint-disable-next-line prefer-destructuring
type = types[0];
}
}
@@ -565,6 +564,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
type={type}
createDropTarget={this.createDashEventsTarget}
screenToLocalTransform={this.ScreenToLocalBoxXf}
+ dontCenter={this.dontCenter}
/>
);
};
@@ -575,7 +575,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
let type: 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | undefined;
const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]);
if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) {
- // eslint-disable-next-line prefer-destructuring
type = types[0];
}
const rows = () => (!this.isStackingView ? 1 : Math.max(1, Math.min(docList.length, Math.floor((this._props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))));
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 5ae08e535..ed0cabd0a 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -41,6 +41,7 @@ interface CSVFieldColumnProps {
columnWidth: number;
numGroupColumns: number;
gridGap: number;
+ dontCenter: 'x' | 'xy' | 'y';
type: 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | undefined;
headings: () => object[];
// I think that stacking view actually has a single column and then supposedly you can add more columns? Unsure
@@ -345,15 +346,6 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
<button type="button" className="collectionStackingView-sectionDelete" onClick={this.deleteColumn}>
<FontAwesomeIcon icon="trash" size="lg" />
</button>
- {/* {evContents === noValueHeader ? null : (
- <div className="collectionStackingView-sectionOptions">
- <Flyout anchorPoint={anchorPoints.TOP_RIGHT} content={this.renderMenu()}>
- <button className="collectionStackingView-sectionOptionButton">
- <FontAwesomeIcon icon="ellipsis-v" size="lg"></FontAwesomeIcon>
- </button>
- </Flyout>
- </div>
- )} */}
</div>
<div
className={'collectionStackingView-collapseBar' + (this._props.headingObject.collapsed === true ? ' active' : '')}
@@ -368,14 +360,20 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
<>
{this._props.Document._columnsHideIfEmpty ? null : headingView}
{this.collapsed ? null : (
- <div>
+ <div
+ style={{
+ margin: 'auto',
+ marginTop: this._props.dontCenter.includes('y') ? undefined : 'auto',
+ marginBottom: this._props.dontCenter.includes('y') ? undefined : 'auto',
+ width: this._props.columnWidth / (uniqueHeadings.length + (this._props.chromeHidden ? 0 : 1) || 1),
+ }}>
<div
key={`${heading}-stack`}
className="collectionStackingView-masonrySingle"
style={{
padding: `${columnYMargin}px ${0}px ${this._props.yMargin}px ${0}px`,
- margin: 'auto',
- width: 'max-content', // singleColumn ? undefined : `${cols * (style.columnWidth + style.gridGap) + 2 * style.xMargin - style.gridGap}px`,
+ margin: this._props.dontCenter.includes('x') ? undefined : 'auto',
+ // width: 'max-content', // singleColumn ? undefined : `${cols * (style.columnWidth + style.gridGap) + 2 * style.xMargin - style.gridGap}px`,
height: 'max-content',
position: 'relative',
gridGap: this._props.gridGap,
@@ -419,11 +417,11 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
const uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx);
return (
<div
- className={'collectionStackingViewFieldColumn' + (SnappingManager.IsDragging ? 'Dragging' : '')}
+ className="collectionStackingViewFieldColumn"
key={heading}
style={{
width: `${100 / (uniqueHeadings.length + (this._props.chromeHidden ? 0 : 1) || 1)}%`,
- height: undefined, // DraggingManager.GetIsDragging() ? "100%" : undefined,
+ height: undefined,
background: this._background,
}}
ref={this.createColumnDropRef}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 6aca8f2ca..5d32482c3 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -122,6 +122,9 @@ export function CollectionSubView<X>() {
);
return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types
}
+ /**
+ * This is the raw, stored list of children on a collection. If you modify this list, the database will be updated
+ */
@computed get childDocList() {
return Cast(this.dataField, listSpec(Doc));
}
@@ -218,7 +221,6 @@ export function CollectionSubView<X>() {
if (!cursors) {
proto.cursors = cursors = new List<CursorField>();
}
- // eslint-disable-next-line no-cond-assign
if (cursors.length > 0 && (ind = cursors.findIndex(entry => entry.data.metadata.id === id)) > -1) {
cursors[ind].setPosition(pos);
} else {
@@ -251,7 +253,7 @@ export function CollectionSubView<X>() {
protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean {
const { docDragData } = de.complete;
- if (docDragData) {
+ if (docDragData && !docDragData.draggedDocuments.includes(this.Document)) {
let added;
const dropAction = docDragData.dropAction || docDragData.userDropAction;
const targetDocments = DocListCast(this.dataDoc[this._props.fieldKey]);
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index ab93abab6..c9e934448 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -34,6 +34,7 @@ import { CollectionLinearView } from './collectionLinear';
import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView';
import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView';
import { CollectionSchemaView } from './collectionSchema/CollectionSchemaView';
+import { CalendarBox } from '../nodes/calendarBox/CalendarBox';
@observer
export class CollectionView extends ViewBoxAnnotatableComponent<CollectionViewProps>() {
@@ -91,7 +92,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<CollectionViewPr
if (type === undefined) return null;
switch (type) {
case CollectionViewType.Schema: return <CollectionSchemaView key="collview" {...props} />;
- case CollectionViewType.Calendar: return <CollectionCalendarView key="collview" {...props} />;
+ case CollectionViewType.Calendar: return <CalendarBox key="collview" {...props} />;
case CollectionViewType.Docking: return <CollectionDockingView key="collview" {...props} />;
case CollectionViewType.Tree: return <CollectionTreeView key="collview" {...props} />;
case CollectionViewType.Multicolumn: return <CollectionMulticolumnView key="collview" {...props} />;
@@ -126,6 +127,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<CollectionViewPr
{ description: 'Masonry', event: () => func(CollectionViewType.Masonry), icon: 'columns' },
{ description: 'Carousel', event: () => func(CollectionViewType.Carousel), icon: 'columns' },
{ description: '3D Carousel', event: () => func(CollectionViewType.Carousel3D), icon: 'columns' },
+ { description: 'Calendar', event: () => func(CollectionViewType.Calendar), icon: 'columns' },
{ description: 'Pivot/Time', event: () => func(CollectionViewType.Time), icon: 'columns' },
{ description: 'Map', event: () => func(CollectionViewType.Map), icon: 'globe-americas' },
{ description: 'Grid', event: () => func(CollectionViewType.Grid), icon: 'th-list' },
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 31b6be927..f56ea9d76 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -57,6 +57,7 @@ interface TabMiniThumbProps {
miniLeft: () => number;
}
+export type TabHTMLElement = HTMLDivElement & { InitTab?: (tab: object) => void };
@observer
class TabMiniThumb extends React.Component<TabMiniThumbProps> {
render() {
@@ -193,8 +194,9 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
.filter(tv => tv._document)
.map(tv => tv._document!);
}
- _mainCont: HTMLDivElement | null = null;
+ _mainCont: TabHTMLElement | null = null;
_tabReaction: IReactionDisposer | undefined;
+ _lastSelection = 0; // time when view was last selected - used to re-select views that get invalidated when selected
/**
* Adds a document to the presentation view
@@ -273,19 +275,24 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs
}
+ // Flag indicating that when a tab is activated, it should not select it's document.
+ // this is used by the link properties menu when it wants to display the link target without selecting the target (which would make the link property window go away since it would no longer be selected)
+ public static DontSelectOnActivate = 'dontSelectOnActivate';
+
+ public static IsSelected = (doc?: Doc) => {
+ return DocumentView.getViews(doc).some(dv => dv?.IsSelected);
+ };
+
static Activate = (tabDoc: Doc) => {
const tab = Array.from(CollectionDockingView.Instance?.tabMap ?? []).find(findTab => findTab.DashDoc === tabDoc && !findTab.contentItem.config.props.keyValue);
tab?.header.parent.setActiveContentItem(tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost)
return tab !== undefined;
};
- // static ActivateTabView(doc: Doc) {
- // const tabView = Array.from(TabDocView._allTabs).find(view => view._document === doc);
- // if (!tabView?._activated && tabView?._document) {
- // TabDocView.Activate(tabView?._document);
- // return tabView;
- // }
- // return undefined;
- // }
+
+ get stack() { return this._props.glContainer.parent.parent; } // prettier-ignore
+ get tab() { return this._props.glContainer.tab; } // prettier-ignore
+ get view() { return this._view; } // prettier-ignore
+
constructor(props: TabDocViewProps) {
super(props);
makeObservable(this);
@@ -299,37 +306,13 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
@observable _hovering = false;
@observable _isActive: boolean = false;
@observable _isAnyChildContentActive = false;
- public static IsSelected = (doc?: Doc) => {
- if (DocumentView.getViews(doc).some(dv => dv?.IsSelected)) {
- return true;
- }
- return false;
- };
- @computed get _isUserActivated() {
- return TabDocView.IsSelected(this._document) || this._isAnyChildContentActive;
- }
- get _isContentActive() {
- return this._isUserActivated || this._hovering;
- }
@observable _document: Doc | undefined = undefined;
@observable _view: DocumentView | undefined = undefined;
+ @observable _forceInvalidateScreenToLocal = 0; // screentolocal is computed outside of react using a dom resize ovbserver. this hack allows the resize observer to trigger a react update
- @computed get layoutDoc() {
- return this._document && Doc.Layout(this._document);
- }
-
- get stack() {
- return this._props.glContainer.parent.parent;
- }
- get tab() {
- return this._props.glContainer.tab;
- }
- get view() {
- return this._view;
- }
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- _lastTab: any;
- _lastView: DocumentView | undefined;
+ @computed get layoutDoc() { return this._document && Doc.Layout(this._document); } // prettier-ignore
+ @computed get isUserActivated() { return TabDocView.IsSelected(this._document) || this._isAnyChildContentActive; } // prettier-ignore
+ @computed get isContentActive() { return this.isUserActivated || this._hovering; } // prettier-ignore
@action
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -413,7 +396,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
color === variant
? DashColor(color)
.fade(
- this._isUserActivated
+ this.isUserActivated
? 0
: this._hovering
? 0.25
@@ -522,19 +505,14 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
this._props.glContainer.layoutManager.off('activeContentItemChanged', this.onActiveContentItemChanged);
}
- // Flag indicating that when a tab is activated, it should not select it's document.
- // this is used by the link properties menu when it wants to display the link target without selecting the target (which would make the link property window go away since it would no longer be selected)
- public static DontSelectOnActivate = 'dontSelectOnActivate';
-
- @action.bound
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- private onActiveContentItemChanged(contentItem: any) {
+ onActiveContentItemChanged = action((contentItem: any) => {
if (!contentItem || (this.stack === contentItem.parent && ((contentItem?.tab === this.tab && !this._isActive) || (contentItem?.tab !== this.tab && this._isActive)))) {
this._activated = this._isActive = !contentItem || contentItem?.tab === this.tab;
if (!this._view && this.tab?.contentItem?.config?.props?.panelName !== TabDocView.DontSelectOnActivate) setTimeout(() => DocumentView.SelectView(this._view, false));
!this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one.
}
- }
+ });
// adds a tab to the layout based on the locaiton parameter which can be:
// close[:{left,right,top,bottom}] - e.g., "close" will close the tab, "close:left" will close the left tab,
@@ -551,7 +529,6 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
const whereMods = whereFields.length > 1 ? (whereFields[1] as OpenWhereMod) : OpenWhereMod.none;
const panelName = whereFields.length > 1 ? whereFields.lastElement() : '';
if (docs[0]?.dockingConfig && !keyValue) return DashboardView.openDashboard(docs[0]);
- // prettier-ignore
switch (whereFields[0]) {
case undefined:
case OpenWhere.lightbox: return LightboxView.Instance.AddDocTab(docs[0], location);
@@ -559,7 +536,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
case OpenWhere.replace: return CollectionDockingView.ReplaceTab(docs[0], whereMods, this.stack, panelName, undefined, keyValue);
case OpenWhere.toggle: return CollectionDockingView.ToggleSplit(docs[0], whereMods, this.stack, TabDocView.DontSelectOnActivate, keyValue);
case OpenWhere.add:default:return CollectionDockingView.AddSplit(docs[0], whereMods, this.stack, undefined, keyValue);
- }
+ } // prettier-ignore
};
remDocTab = (doc: Doc | Doc[]) => {
if (doc === this._document) {
@@ -571,8 +548,6 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
};
getCurrentFrame = () => NumCast(Cast(PresBox.Instance.activeItem.presentation_targetDoc, Doc, null)._currentFrame);
-
- @action
focusFunc = () => {
if (!this.tab.header.parent._activeContentItem || this.tab.header.parent._activeContentItem !== this.tab.contentItem) {
this.tab.header.parent.setActiveContentItem(this.tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost)
@@ -580,7 +555,6 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
return undefined;
};
active = () => this._isActive;
- @observable _forceInvalidateScreenToLocal = 0;
ScreenToLocalTransform = () => {
this._forceInvalidateScreenToLocal;
const { translateX, translateY } = ClientUtils.GetScreenTransform(this._mainCont?.children?.[0] as HTMLElement);
@@ -594,47 +568,44 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
whenChildContentActiveChanges = (isActive: boolean) => {
this._isAnyChildContentActive = isActive;
};
- isContentActive = () => this._isContentActive;
+ isContentActiveFunc = () => this.isContentActive;
waitForDoubleClick = () => (SnappingManager.ExploreMode ? 'never' : undefined);
- @computed get docView() {
- return !this._activated || !this._document ? null : (
- <>
- <DocumentView
- key={this._document[Id]}
- ref={action((r: DocumentView) => {
- this._lastView && DocumentView.removeView(this._lastView);
- this._view = r;
- this._lastView = this._view;
- })}
- renderDepth={0}
- LayoutTemplateString={this._props.keyValue ? KeyValueBox.LayoutString() : undefined}
- hideTitle={this._props.keyValue}
- Document={this._document}
- TemplateDataDocument={!Doc.AreProtosEqual(this._document[DocData], this._document) ? this._document[DocData] : undefined}
- waitForDoubleClickToClick={this.waitForDoubleClick}
- isContentActive={this.isContentActive}
- isDocumentActive={returnFalse}
- PanelWidth={this.PanelWidth}
- PanelHeight={this.PanelHeight}
- styleProvider={DefaultStyleProvider}
- childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyFilter}
- childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyFilter}
- searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist}
- addDocument={undefined}
- removeDocument={this.remDocTab}
- addDocTab={this.addDocTab}
- suppressSetHeight={!!this._document._layout_fitWidth}
- ScreenToLocalTransform={this.ScreenToLocalTransform}
- dontCenter="y"
- whenChildContentsActiveChanged={this.whenChildContentActiveChanges}
- focus={this.focusFunc}
- containerViewPath={returnEmptyDocViewList}
- pinToPres={TabDocView.PinDoc}
- />
- {this.disableMinimap() ? null : <TabMinimapView key="minimap" addDocTab={this.addDocTab} PanelHeight={this.PanelHeight} PanelWidth={this.PanelWidth} background={this.miniMapColor} document={this._document} tabView={this.tabView} />}
- </>
- );
- }
+ renderDocView = (doc: Doc) => (
+ <DocumentView
+ key={doc[Id]}
+ ref={action((r: DocumentView) => {
+ const now = Date.now();
+ this._lastSelection = this._view?.IsSelected ? now : this._lastSelection;
+ if (this._view) DocumentView.removeView(this._view);
+ this._view = r;
+ if (this._view && now - this._lastSelection < 1000) this._view.select(false);
+ })}
+ renderDepth={0}
+ LayoutTemplateString={this._props.keyValue ? KeyValueBox.LayoutString() : undefined}
+ hideTitle={this._props.keyValue}
+ Document={doc}
+ TemplateDataDocument={!Doc.AreProtosEqual(doc[DocData], doc) ? doc[DocData] : undefined}
+ waitForDoubleClickToClick={this.waitForDoubleClick}
+ isContentActive={this.isContentActiveFunc}
+ isDocumentActive={returnFalse}
+ PanelWidth={this.PanelWidth}
+ PanelHeight={this.PanelHeight}
+ styleProvider={DefaultStyleProvider}
+ childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyFilter}
+ childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyFilter}
+ searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist}
+ addDocument={undefined}
+ removeDocument={this.remDocTab}
+ addDocTab={this.addDocTab}
+ suppressSetHeight={!!doc._layout_fitWidth}
+ ScreenToLocalTransform={this.ScreenToLocalTransform}
+ dontCenter="y"
+ whenChildContentsActiveChanged={this.whenChildContentActiveChanges}
+ focus={this.focusFunc}
+ containerViewPath={returnEmptyDocViewList}
+ pinToPres={TabDocView.PinDoc}
+ />
+ );
render() {
return (
@@ -647,23 +618,21 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
onPointerLeave={action(() => { this._hovering = false; })} // prettier-ignore
onDragOver={action(() => { this._hovering = true; })} // prettier-ignore
onDragLeave={action(() => { this._hovering = false; })} // prettier-ignore
- ref={ref => {
+ ref={(ref: TabHTMLElement) => {
+ // "add" an InitTab function to this div to call from tabCreated in CollectionDockingView when div is reused
this._mainCont = ref;
if (this._mainCont) {
- if (this._lastTab) {
- this._view && DocumentView.removeView(this._view);
- }
- this._lastTab = this.tab;
- (this._mainCont as { InitTab?: (tab: object) => void }).InitTab = (tab: object) => this.init(tab, this._document);
- DocServer.GetRefField(this._props.documentId).then(
- action(doc => {
- doc instanceof Doc && (this._document = doc) && this.tab && this.init(this.tab, this._document);
- })
- );
- ref && new ResizeObserver(action(() => this._forceInvalidateScreenToLocal++)).observe(ref);
+ this._mainCont.InitTab = (tab: object) => this.init(tab, this._document);
+ DocServer.GetRefField(this._props.documentId).then(action(doc => {
+ doc instanceof Doc && (this._document = doc) && this.tab && this.init(this.tab, this._document);
+ })); // prettier-ignore
+ new ResizeObserver(action(() => this._forceInvalidateScreenToLocal++)).observe(this._mainCont);
}
}}>
- {this.docView}
+ {!this._activated || !this._document ? null : this.renderDocView(this._document)}
+ {this.disableMinimap() || !this._document ? null : (
+ <TabMinimapView key="minimap" addDocTab={this.addDocTab} PanelHeight={this.PanelHeight} PanelWidth={this.PanelWidth} background={this.miniMapColor} document={this._document} tabView={this.tabView} />
+ )}
</div>
);
}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 015f77ffd..5444a7a57 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -474,7 +474,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
};
docTransform = () => this.refTransform(this._dref?.ContentDiv);
getTransform = () => this.refTransform(this._tref.current);
- embeddedPanelWidth = () => this._props.panelWidth() / (this.treeView._props.NativeDimScaling?.() || 1);
+ embeddedPanelWidth = () => this._props.panelWidth() / (this.treeView._props.NativeDimScaling?.() || 1) - 3 /* paddingRight for bullet */;
embeddedPanelHeight = () => {
const layoutDoc = (temp => temp && Doc.expandTemplateLayout(temp, this.Document))(this.treeView._props.childLayoutTemplate?.()) || this.layoutDoc;
return Math.min(
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index ad1223097..ccce2662a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable react/jsx-props-no-spreading */
import { Bezier } from 'bezier-js';
import { Colors } from 'browndash-components';
import { Property } from 'csstype';
@@ -1179,7 +1178,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
for (let j = 0; j < otherCtrlPts.length - 3; j += 4) {
const neighboringSegment = i === j || i === j - 4 || i === j + 4;
// Ensuring that the curve intersected by the eraser is not checked for further ink intersections.
- // eslint-disable-next-line no-continue
if (ink?.Document === otherInk.Document && neighboringSegment) continue;
const otherCurve = new Bezier(otherCtrlPts.slice(j, j + 4).map(p => ({ x: p.X, y: p.Y })));
@@ -1553,8 +1551,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const childData = entry.pair.data;
return (
<CollectionFreeFormDocumentView
- // eslint-disable-next-line react/jsx-props-no-spreading, @typescript-eslint/no-explicit-any
- {...(OmitKeys(entry, ['replica', 'pair']).omit as any)}
+ {...(OmitKeys(entry, ['replica', 'pair']).omit as { x: number; y: number; z: number; width: number; height: number })}
key={childLayout[Id] + (entry.replica || '')}
Document={childLayout}
reactParent={this}
@@ -1858,7 +1855,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (!code.includes('dashDiv')) {
const script = CompileScript(code, { params: { docView: 'any' }, typecheck: false, editable: true });
if (script.compiled) script.run({ this: this.DocumentView?.() });
- // eslint-disable-next-line no-eval
} else code && !first && eval?.(code);
},
{ fireImmediately: true }
@@ -1879,24 +1875,28 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
Object.values(this._disposers).forEach(disposer => disposer?.());
}
- updateIcon = (usePanelDimensions?: boolean) =>
- UpdateIcon(
- this.layoutDoc[Id] + '_icon_' + new Date().getTime(),
- this.DocumentView?.().ContentDiv!,
- usePanelDimensions ? this._props.PanelWidth() : NumCast(this.layoutDoc._width),
- usePanelDimensions ? this._props.PanelHeight() : NumCast(this.layoutDoc._height),
- this._props.PanelWidth(),
- this._props.PanelHeight(),
- 0,
- 1,
- false,
- '',
- (iconFile, nativeWidth, nativeHeight) => {
- this.dataDoc.icon = new ImageField(iconFile);
- this.dataDoc.icon_nativeWidth = nativeWidth;
- this.dataDoc.icon_nativeHeight = nativeHeight;
- }
- );
+ updateIcon = (usePanelDimensions?: boolean) => {
+ const contentDiv = this.DocumentView?.().ContentDiv;
+ return !contentDiv
+ ? new Promise<void>(res => res())
+ : UpdateIcon(
+ this.layoutDoc[Id] + '_icon_' + new Date().getTime(),
+ contentDiv,
+ usePanelDimensions ? this._props.PanelWidth() : NumCast(this.layoutDoc._width),
+ usePanelDimensions ? this._props.PanelHeight() : NumCast(this.layoutDoc._height),
+ this._props.PanelWidth(),
+ this._props.PanelHeight(),
+ 0,
+ 1,
+ false,
+ '',
+ (iconFile, nativeWidth, nativeHeight) => {
+ this.dataDoc.icon = new ImageField(iconFile);
+ this.dataDoc.icon_nativeWidth = nativeWidth;
+ this.dataDoc.icon_nativeHeight = nativeHeight;
+ }
+ );
+ };
@action
onCursorMove = (e: React.PointerEvent) => {
diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
index 717081666..534f67927 100644
--- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
+++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
@@ -179,7 +179,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() {
ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
})}>
{FaceRecognitionHandler.UniqueFaceImages(this.Document).map((doc, i) => {
- const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.');
+ const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)])?.url.href.split('.') ?? ['-missing-', '.png'];
return (
<div
className="image-wrapper"
@@ -264,6 +264,7 @@ export class FaceCollectionBox extends ViewBoxBaseComponent<FieldViewProps>() {
isContentActive={returnTrue}
isAnyChildContentActive={returnTrue}
childHideDecorations={true}
+ dontCenter="y"
/>
</div>
);
diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx
index e419e522c..033d1590d 100644
--- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx
+++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx
@@ -139,9 +139,9 @@ export class ImageLabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
toggleDisplayInformation = () => {
this._displayImageInformation = !this._displayImageInformation;
if (this._displayImageInformation) {
- this._selectedImages.forEach(doc => (doc[DocData].showTags = true));
+ this._selectedImages.forEach(doc => (doc._layout_showTags = true));
} else {
- this._selectedImages.forEach(doc => (doc[DocData].showTags = false));
+ this._selectedImages.forEach(doc => (doc._layout_showTags = false));
}
};
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index bfb1d12cb..f1dba58ce 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -162,8 +162,8 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
pasteImageBitmap((data: any, error: any) => {
error && console.log(error);
data &&
- ClientUtils.convertDataUri(data, this._props.Document[Id] + '-thumb-frozen').then(returnedfilename => {
- this._props.Document['thumb-frozen'] = new ImageField(returnedfilename);
+ ClientUtils.convertDataUri(data, this._props.Document[Id] + '_icon_' + new Date().getTime()).then(returnedfilename => {
+ this._props.Document[DocData].icon = new ImageField(returnedfilename);
});
})
);
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index 61bd0241c..5c41fee37 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -9,7 +9,7 @@ import { emptyFunction } from '../../../../Utils';
import { Docs } from '../../../documents/Documents';
import { DragManager } from '../../../util/DragManager';
import { Transform } from '../../../util/Transform';
-import { undoBatch } from '../../../util/UndoManager';
+import { undoable, undoBatch } from '../../../util/UndoManager';
import { ContextMenu } from '../../ContextMenu';
import { ContextMenuProps } from '../../ContextMenuItem';
import { DocumentView } from '../../nodes/DocumentView';
@@ -221,13 +221,13 @@ export class CollectionGridView extends CollectionSubView() {
});
if (this.Document.gridStartCompaction) {
- undoBatch(() => {
+ undoable(() => {
this.Document.gridCompaction = this.Document.gridStartCompaction;
this.setLayoutList(savedLayouts);
- })();
+ }, 'start grid compaction')();
this.Document.gridStartCompaction = undefined;
} else {
- undoBatch(() => this.setLayoutList(savedLayouts))();
+ undoable(() => this.setLayoutList(savedLayouts), 'start grid compaction')();
}
}
};
@@ -315,9 +315,9 @@ export class CollectionGridView extends CollectionSubView() {
e,
returnFalse,
action(() => {
- undoBatch(() => {
+ undoable(() => {
this.Document.gridRowHeight = this._rowHeight;
- })();
+ }, 'changing row height')();
this._rowHeight = undefined;
}),
emptyFunction,
@@ -360,13 +360,14 @@ export class CollectionGridView extends CollectionSubView() {
returnFalse,
(clickEv: PointerEvent, doubleTap?: boolean) => {
if (doubleTap && !clickEv.button) {
- undoBatch(
+ undoable(
action(() => {
const text = Docs.Create.TextDocument('', { _width: 150, _height: 50 });
Doc.SetSelectOnLoad(text); // track the new text box so we can give it a prop that tells it to focus itself when it's displayed
Doc.AddDocToList(this.Document, this._props.fieldKey, text);
this.setLayoutList(this.addLayoutItem(this.savedLayoutList, this.makeLayoutItem(text, this.screenToCell(clickEv.clientX, clickEv.clientY))));
- })
+ }),
+ 'create grid text'
)();
}
},
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss
index 06d78c39e..9ed247d50 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss
@@ -1,5 +1,6 @@
.collectionMulticolumnView_drop {
height: 100%;
+ width: 100%;
top: 0;
left: 0;
position: absolute;
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss
index 0d49fabaa..91779065d 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss
@@ -1,5 +1,6 @@
.collectionMultirowView_drop {
height: 100%;
+ width: 100%;
top: 0;
left: 0;
position: absolute;
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 68d287ac8..c08d19a6b 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -2,20 +2,23 @@
import { Colors } from 'browndash-components';
import { action, runInAction } from 'mobx';
import { aggregateBounds } from '../../../Utils';
-import { Doc, DocListCast, FieldType, NumListCast, Opt } from '../../../fields/Doc';
+import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
import { InkTool } from '../../../fields/InkField';
-import { List } from '../../../fields/List';
import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
import { WebField } from '../../../fields/URLField';
import { Gestures } from '../../../pen-gestures/GestureTypes';
-import { DocumentType } from '../../documents/DocumentTypes';
+import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
+import { Docs } from '../../documents/Documents';
import { LinkManager } from '../../util/LinkManager';
import { ScriptingGlobals } from '../../util/ScriptingGlobals';
+import { SnappingManager } from '../../util/SnappingManager';
import { UndoManager, undoable } from '../../util/UndoManager';
import { GestureOverlay } from '../GestureOverlay';
import { InkingStroke } from '../InkingStroke';
import { CollectionFreeFormView, MarqueeView } from '../collections/collectionFreeForm';
+import { MainView } from '../MainView';
+import { PropertiesView } from '../PropertiesView';
import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView';
import {
ActiveEraserWidth,
@@ -36,6 +39,7 @@ import { ImageBox } from '../nodes/ImageBox';
import { VideoBox } from '../nodes/VideoBox';
import { WebBox } from '../nodes/WebBox';
import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
+import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup';
// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function IsNoneSelected() {
@@ -131,22 +135,27 @@ ScriptingGlobals.add(function toggleOverlay(checkResult?: boolean) {
});
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function showFreeform(attr: 'center' | 'grid' | 'snaplines' | 'clusters' | 'viewAll' | 'fitOnce', checkResult?: boolean, persist?: boolean) {
+ScriptingGlobals.add(function showFreeform(attr: 'hcenter' | 'vcenter' | 'grid' | 'snaplines' | 'clusters' | 'viewAll' | 'fitOnce', checkResult?: boolean, persist?: boolean) {
const selected = DocumentView.SelectedDocs().lastElement();
+
+ function isAttrFiltered(attribute: string) {
+ return StrListCast(selected._childFilters).some(filter => filter.includes(attribute));
+ }
+
// prettier-ignore
- const map: Map<'flashcards' | 'center' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'links' | 'like' | 'star' | 'idea' | 'chat' | '1' | '2' | '3' | '4',
+ const map: Map<'flashcards' | 'hcenter' | 'vcenter' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'chat' | 'up' | 'down' | 'pile' | 'toggle-chat' | 'tag',
{
waitForRender?: boolean;
checkResult: (doc: Doc) => boolean;
setDoc: (doc: Doc, dv: DocumentView) => void;
}> = new Map([
['grid', {
- checkResult: (doc:Doc) => BoolCast(doc?._freeform_backgroundGrid, false),
- setDoc: (doc:Doc) => { doc._freeform_backgroundGrid = !doc._freeform_backgroundGrid; },
+ checkResult: (doc: Doc) => BoolCast(doc?._freeform_backgroundGrid, false),
+ setDoc: (doc: Doc) => { doc._freeform_backgroundGrid = !doc._freeform_backgroundGrid; },
}],
['snaplines', {
- checkResult: (doc:Doc) => BoolCast(doc?._freeform_snapLines, false),
- setDoc: (doc:Doc) => { doc._freeform_snapLines = !doc._freeform_snapLines; },
+ checkResult: (doc: Doc) => BoolCast(doc?._freeform_snapLines, false),
+ setDoc: (doc: Doc) => { doc._freeform_snapLines = !doc._freeform_snapLines; },
}],
['viewAll', {
checkResult: (doc: Doc) => BoolCast(doc?._freeform_fitContentsToBox, false),
@@ -156,126 +165,138 @@ ScriptingGlobals.add(function showFreeform(attr: 'center' | 'grid' | 'snaplines'
else (dv.ComponentView as CollectionFreeFormView)?.fitContentOnce();
},
}],
- ['center', {
- checkResult: (doc:Doc) => BoolCast(doc?._stacking_alignCenter, false),
- setDoc: (doc:Doc) => { doc._stacking_alignCenter = !doc._stacking_alignCenter; },
+ ['vcenter', {
+ checkResult: (doc:Doc) => !StrCast(doc?._layout_dontCenter).includes('y'),
+ setDoc: (doc:Doc) => { doc._layout_dontCenter = StrCast(doc.layout_dontCenter).includes('y') ? StrCast(doc.layout_dontCenter).replace(/y/,"") : StrCast(doc.layout_dontCenter) + 'y'; },
+ }],
+ ['hcenter', {
+ checkResult: (doc:Doc) => !StrCast(doc?._layout_dontCenter).includes('x'),
+ setDoc: (doc:Doc) => { doc._layout_dontCenter = StrCast(doc.layout_dontCenter).includes('x') ? StrCast(doc.layout_dontCenter).replace(/x/,"") : 'x'+ StrCast(doc.layout_dontCenter); },
}],
['clusters', {
waitForRender: true, // flags that undo batch should terminate after a re-render giving the script the chance to fire
- checkResult: (doc:Doc) => BoolCast(doc?._freeform_useClusters, false),
- setDoc: (doc:Doc) => { doc._freeform_useClusters = !doc._freeform_useClusters; },
+ checkResult: (doc: Doc) => BoolCast(doc?._freeform_useClusters, false),
+ setDoc: (doc: Doc) => { doc._freeform_useClusters = !doc._freeform_useClusters; },
}],
['flashcards', {
checkResult: (doc: Doc) => BoolCast(Doc.UserDoc().defaultToFlashcards, false),
- setDoc: (doc: Doc, dv: DocumentView) => Doc.UserDoc().defaultToFlashcards = !Doc.UserDoc().defaultToFlashcards,
+ setDoc: (doc: Doc, dv: DocumentView) => { Doc.UserDoc().defaultToFlashcards = !Doc.UserDoc().defaultToFlashcards}, // prettier-ignore
}],
['time', {
checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "time",
- setDoc: (doc: Doc, dv: DocumentView) => doc.cardSort = "time",
+ setDoc: (doc: Doc, dv: DocumentView) => { doc.cardSort === "time" ? doc.cardSort = '' : doc.cardSort = 'time'}, // prettier-ignore
}],
['docType', {
checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "type",
- setDoc: (doc: Doc, dv: DocumentView) => doc.cardSort = "type",
+ setDoc: (doc: Doc, dv: DocumentView) => { doc.cardSort === "type" ? doc.cardSort = '' : doc.cardSort = 'type'}, // prettier-ignore
}],
['color', {
checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "color",
- setDoc: (doc: Doc, dv: DocumentView) => doc.cardSort = "color",
+ setDoc: (doc: Doc, dv: DocumentView) => { doc.cardSort === "color" ? doc.cardSort = '' : doc.cardSort = 'color'}, // prettier-ignore
}],
- ['links', {
- checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "links",
- setDoc: (doc: Doc, dv: DocumentView) => doc.cardSort = "links",
+ ['tag', {
+ checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "tag",
+ setDoc: (doc: Doc, dv: DocumentView) => { doc.cardSort === "tag" ? doc.cardSort = '' : doc.cardSort = 'tag'}, // prettier-ignore
}],
- ['like', {
- checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "custom" && StrCast(doc?.cardSort_customField) === "like",
+ ['up', {
+ checkResult: (doc: Doc) => BoolCast(!doc?.cardSort_isDesc),
setDoc: (doc: Doc, dv: DocumentView) => {
- doc.cardSort = "custom";
- doc.cardSort_customField = "like";
- doc.cardSort_visibleSortGroups = new List<number>();
- }
+ doc.cardSort_isDesc = false;
+ },
}],
- ['star', {
- checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "custom" && StrCast(doc?.cardSort_customField) === "star",
+ ['down', {
+ checkResult: (doc: Doc) => BoolCast(doc?.cardSort_isDesc),
setDoc: (doc: Doc, dv: DocumentView) => {
- doc.cardSort = "custom";
- doc.cardSort_customField = "star";
- doc.cardSort_visibleSortGroups = new List<number>();
- }
+ doc.cardSort_isDesc = true;
+ },
}],
- ['idea', {
- checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "custom" && StrCast(doc?.cardSort_customField) === "idea",
+ ['toggle-chat', {
+ checkResult: (doc: Doc) => GPTPopup.Instance.visible,
setDoc: (doc: Doc, dv: DocumentView) => {
- doc.cardSort = "custom";
- doc.cardSort_customField = "idea";
- doc.cardSort_visibleSortGroups = new List<number>();
- }
+ if (GPTPopup.Instance.visible){
+ doc.cardSort = ''
+ GPTPopup.Instance.setVisible(false);
+
+ } else {
+ GPTPopup.Instance.setVisible(true);
+ GPTPopup.Instance.setMode(GPTPopupMode.CARD);
+ GPTPopup.Instance.setCardsDoneLoading(true);
+
+ }
+
+
+ },
}],
- ['chat', {
- checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "custom" && StrCast(doc?.cardSort_customField) === "chat",
+ ['pile', {
+ checkResult: (doc: Doc) => doc._type_collection == CollectionViewType.Freeform,
setDoc: (doc: Doc, dv: DocumentView) => {
- doc.cardSort = "custom";
- doc.cardSort_customField = "chat";
- doc.cardSort_visibleSortGroups = new List<number>();
+ doc._type_collection = CollectionViewType.Freeform;
+ const newCol = Docs.Create.CarouselDocument(DocListCast(doc[Doc.LayoutFieldKey(doc)]), {
+ _width: 250,
+ _height: 200,
+ _layout_fitWidth: false,
+ _layout_autoHeight: true,
+ });
+
+
+ const iconMap: { [key: number]: string } = {
+ 0: 'star',
+ 1: 'heart',
+ 2: 'cloud',
+ 3: 'bolt'
+ };
+
+ for (let i=0; i<4; i++){
+ if (isAttrFiltered(iconMap[i])){
+ newCol[iconMap[i]] = true
+ }
+ }
+
+ newCol && dv.ComponentView?.addDocument?.(newCol);
+ DocumentView.showDocument(newCol, { willZoomCentered: true })
+
},
}],
]);
- for (let i = 0; i < 8; i++) {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- map.set((i + 1 + '') as any, {
- checkResult: (doc: Doc) => NumListCast(doc?.cardSort_visibleSortGroups).includes(i),
- setDoc: (doc: Doc, dv: DocumentView) => {
- const list = NumListCast(doc.cardSort_visibleSortGroups);
- doc.cardSort_visibleSortGroups = new List<number>(list.includes(i) ? list.filter(d => d !== i) : [...list, i]);
- },
- });
- }
if (checkResult) {
return map.get(attr)?.checkResult(selected);
}
+
const batch = map.get(attr)?.waitForRender ? UndoManager.StartBatch('set freeform attribute') : { end: () => {} };
DocumentView.Selected().map(dv => map.get(attr)?.setDoc(dv.layoutDoc, dv));
setTimeout(() => batch.end(), 100);
return undefined;
});
-ScriptingGlobals.add(function cardHasLabel(label: string) {
+/**
+ * Applies (or removes) a filter to the selected document for the specified tag
+ * NOTE: this also opens the filter panel if the settings button is clicked (probably should be a different function)
+ */
+// eslint-disable-next-line prefer-arrow-callback
+ScriptingGlobals.add(function setTagFilter(tag: string, added: boolean, checkResult?: boolean) {
const selected = DocumentView.SelectedDocs().lastElement();
- const labelNum = Number(label) - 1;
- return labelNum < 4 || (selected && DocListCast(selected[Doc.LayoutFieldKey(selected)]).some(doc => doc[StrCast(selected.cardSort_customField)] == labelNum));
-}, '');
+ const isOptions = tag === '-opts-';
-// ScriptingGlobals.add(function setCardSortAttr(attr: 'time' | 'docType' | 'color', value: any, checkResult?: boolean) {
-// // const editorView = RichTextMenu.Instance?.TextView?.EditorView;
-// const selected = SelectionManager.Docs.lastElement();
-// // prettier-ignore
-// const map: Map<'time' | 'docType' | 'color', { waitForRender?: boolean, checkResult: (doc:Doc) => any; setDoc: (doc:Doc, dv:DocumentView) => void;}> = new Map([
-// ['time', {
-// checkResult: (doc:Doc) => StrCast(doc?.cardSort),
-// setDoc: (doc:Doc,dv:DocumentView) => doc.cardSort = "time",
-// }],
-// ['docType', {
-// checkResult: (doc:Doc) => StrCast(doc?.cardSort),
-// setDoc: (doc:Doc,dv:DocumentView) => doc.cardSort = "type",
-// }],
-// ['color', {
-// checkResult: (doc:Doc) => StrCast(doc?.cardSort),
-// setDoc: (doc:Doc,dv:DocumentView) => doc.cardSort = "color",
-// }],
-// // ['custom', {
-// // checkResult: () => RichTextMenu.Instance.textAlign,
-// // setDoc: () => value && editorView?.state ? RichTextMenu.Instance.align(editorView, editorView.dispatch, value):(Doc.UserDoc().textAlign = value),
-// // }]
-// // ,
-// ]);
-
-// if (checkResult) {
-// return map.get(attr)?.checkResult(selected);
-// }
-
-// console.log('hey')
-// SelectionManager.Views.map(dv => map.get(attr)?.setDoc(dv.layoutDoc, dv));
-// console.log('success')
-// });
+ if (checkResult) {
+ return isOptions
+ ? false
+ : StrListCast(selected._childFilters) // check all filters for one that filters tags:value where value is the tag's name
+ .map(filter => filter.split(Doc.FilterSep))
+ .some(([key, val]) => key === 'tags' && val === tag);
+ }
+
+ if (!isOptions) {
+ added ? Doc.setDocFilter(selected, 'tags', tag, 'check') : Doc.setDocFilter(selected, 'tags', tag, 'remove');
+ } else {
+ SnappingManager.PropertiesWidth < 5 && SnappingManager.SetPropertiesWidth(0);
+ SnappingManager.SetPropertiesWidth(MainView.Instance.propertiesWidth() < 15 ? 250 : 0);
+ PropertiesView.Instance?.CloseAll();
+ runInAction(() => (PropertiesView.Instance.openFilters = SnappingManager.PropertiesWidth > 5));
+ }
+
+ return undefined;
+}, '');
// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highlight' | 'fontSize' | 'alignment', value: string | number, checkResult?: boolean) {
@@ -310,6 +331,7 @@ ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highligh
]);
if (checkResult) {
+ // console.log(map.get(attr)?.checkResult() + "font check result")
return map.get(attr)?.checkResult();
}
map.get(attr)?.setDoc?.();
@@ -470,6 +492,7 @@ function setActiveTool(tool: InkTool | Gestures, keepPrim: boolean, checkResult?
ScriptingGlobals.add(setActiveTool, 'sets the active ink tool mode');
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function activeEraserTool() {
return StrCast(Doc.UserDoc().activeEraserTool, InkTool.StrokeEraser);
}, 'returns the current eraser tool');
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 1eae163df..39a2e3a31 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -3,7 +3,7 @@ import { Tooltip } from '@mui/material';
import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { returnFalse, returnNone, setupMoveUpEvents } from '../../../ClientUtils';
+import { returnFalse, returnNone, returnZero, setupMoveUpEvents } from '../../../ClientUtils';
import { emptyFunction } from '../../../Utils';
import { Doc, Opt } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
@@ -303,6 +303,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
<DocumentView
// eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
+ fitWidth={undefined}
+ NativeHeight={returnZero}
+ NativeWidth={returnZero}
ignoreUsePath={layoutString ? true : undefined}
renderDepth={this.props.renderDepth + 1}
LayoutTemplateString={layoutString}
@@ -310,8 +313,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
containerViewPath={this.DocumentView?.().docViewPath}
moveDocument={whichSlot.endsWith('1') ? this.moveDoc1 : this.moveDoc2}
removeDocument={whichSlot.endsWith('1') ? this.remDoc1 : this.remDoc2}
- NativeWidth={this.layoutWidth}
- NativeHeight={this.layoutHeight}
isContentActive={emptyFunction}
isDocumentActive={returnFalse}
whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c279badf4..85fd42ddf 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -67,6 +67,7 @@ export interface DocumentViewProps extends FieldViewSharedProps {
hideCaptions?: boolean;
contentPointerEvents?: Property.PointerEvents | undefined; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
dontCenter?: 'x' | 'y' | 'xy';
+ showTags?: boolean;
childHideDecorationTitle?: boolean;
childHideResizeHandles?: boolean;
childDragAction?: dropActionType; // allows child documents to be dragged out of collection without holding the embedKey or dragging the doc decorations title bar.
@@ -1137,6 +1138,10 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
@observable public static CurrentlyPlaying: DocumentView[] = []; // audio or video media views that are currently playing
@observable public TagPanelHeight = 0;
+ @computed get showTags() {
+ return this.Document._layout_showTags || this._props.showTags;
+ }
+
@computed private get shouldNotScale() {
return (this.layout_fitWidth && !this.nativeWidth) || this.ComponentView?.isUnstyledView?.();
}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index dd71fd946..683edba16 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -1,5 +1,3 @@
-/* eslint-disable react/no-unused-prop-types */
-/* eslint-disable react/require-default-props */
import { Property } from 'csstype';
import { computed } from 'mobx';
import { observer } from 'mobx-react';
@@ -21,6 +19,7 @@ export type FocusFuncType = (doc: Doc, options: FocusViewOptions) => Opt<number>
// eslint-disable-next-line no-use-before-define
export type StyleProviderFuncType = (
doc: Opt<Doc>,
+ // eslint-disable-next-line no-use-before-define
props: Opt<FieldViewProps>,
property: string
) =>
@@ -65,6 +64,7 @@ export interface FieldViewSharedProps {
containerViewPath?: () => DocumentView[];
fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document
isGroupActive?: () => string | undefined; // is this document part of a group that is active
+ // eslint-disable-next-line no-use-before-define
setContentViewBox?: (view: ViewBoxInterface<FieldViewProps>) => void; // called by rendered field's viewBox so that DocumentView can make direct calls to the viewBox
PanelWidth: () => number;
PanelHeight: () => number;
@@ -82,6 +82,7 @@ export interface FieldViewSharedProps {
// eslint-disable-next-line no-use-before-define
onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined;
fitWidth?: (doc: Doc) => boolean | undefined;
+ dontCenter?: 'x' | 'y' | 'xy' | undefined;
searchFilterDocs: () => Doc[];
showTitle?: () => string;
whenChildContentsActiveChanged: (isActive: boolean) => void;
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
index f2f7f39bb..cb0c4d188 100644
--- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
@@ -192,7 +192,7 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
} else {
text = script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result as string;
// text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily);
- getStyle = (val: string) => ({ fontFamily: val });
+ if (this.Document.title === 'Font') getStyle = (val: string) => ({ fontFamily: val }); // bcz: major hack to style the font dropdown items --- needs to become part of the dropdown's metadata
}
// Get items to place into the list
@@ -266,26 +266,31 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
// Colors
const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string;
const items = DocListCast(this.dataDoc.data);
- const multiDoc = this.Document;
+ const selectedItems = items.filter(itemDoc => ScriptCast(itemDoc.onClick).script.run({ this: itemDoc, value: undefined, _readOnly_: true }).result).map(item => StrCast(item.toolType));
return (
<MultiToggle
tooltip={`Toggle ${tooltip}`}
type={Type.PRIM}
color={color}
- onPointerDown={e => script && !toggleStatus && setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => script.run({ this: multiDoc, value: undefined, _readOnly_: false }))}
+ multiSelect={true}
+ onPointerDown={e => script && !toggleStatus && setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => script.run({ this: this.Document, value: undefined, _readOnly_: false }))}
isToggle={script ? true : false}
toggleStatus={toggleStatus}
//background={SnappingManager.userBackgroundColor}
label={this.label}
- items={DocListCast(this.dataDoc.data).map(item => ({
+ items={items.map(item => ({
icon: <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={StrCast(item.icon) as IconProp} color={color} />,
tooltip: StrCast(item.toolTip),
val: StrCast(item.toolType),
}))}
- selectedVal={StrCast(items.find(itemDoc => ScriptCast(itemDoc.onClick).script.run({ this: itemDoc, value: undefined, _readOnly_: true }).result)?.toolType ?? StrCast(multiDoc.toolType))}
- setSelectedVal={(val: string | number) => {
- const itemDoc = items.find(item => item.toolType === val);
- itemDoc && ScriptCast(itemDoc.onClick).script.run({ this: itemDoc, value: val, _readOnly_: false });
+ selectedItems={selectedItems}
+ onSelectionChange={(val: (string | number) | (string | number)[], added: boolean) => {
+ // note: the multitoggle is telling us whether the selection was toggled on or off, but we ignore this since we know the state of all the buttons
+ // and control it through the selectedItems prop. Therefore, the callback script will have to re-determine the toggle information.
+ // it would be better to pas the 'added' flag to the callback script, but our script generator from currentUserUtils makes it hard to define
+ // arbitrary parameter variables (but it could be done as a special case or with additional effort when creating the sript)
+ const itemsChanged = items.filter(item => (val instanceof Array ? val.includes(item.toolType as string | number) : item.toolType === val));
+ itemsChanged.forEach(itemDoc => ScriptCast(itemDoc.onClick).script.run({ this: itemDoc, _added_: added, itemDoc, _readOnly_: false }));
}}
/>
);
@@ -345,7 +350,7 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
@computed get editableText() {
const script = ScriptCast(this.Document.script);
- const checkResult = script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result;
+ const checkResult = script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result as string;
const setValue = (value: string) => script?.script.run({ this: this.Document, value, _readOnly_: false }).result as boolean;
diff --git a/src/client/views/nodes/IconTagBox.scss b/src/client/views/nodes/IconTagBox.scss
new file mode 100644
index 000000000..90cc06092
--- /dev/null
+++ b/src/client/views/nodes/IconTagBox.scss
@@ -0,0 +1,26 @@
+@import '../global/globalCssVariables.module.scss';
+
+.card-button-container {
+ display: flex;
+ position: relative;
+ pointer-events: none;
+ background-color: rgb(218, 218, 218);
+ border-radius: 50px;
+ align-items: center;
+ gap: 5px;
+ padding-left: 5px;
+ padding-right: 5px;
+ padding-top: 2px;
+ padding-bottom: 2px;
+
+ button {
+ pointer-events: auto;
+ width: 20px;
+ height: 20px;
+ margin: auto;
+ padding: 0;
+ border-radius: 50%;
+ background-color: $dark-gray;
+ background-color: transparent;
+ }
+}
diff --git a/src/client/views/nodes/IconTagBox.tsx b/src/client/views/nodes/IconTagBox.tsx
new file mode 100644
index 000000000..8faf8ffa5
--- /dev/null
+++ b/src/client/views/nodes/IconTagBox.tsx
@@ -0,0 +1,92 @@
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Tooltip } from '@mui/material';
+import { computed, makeObservable } from 'mobx';
+import { observer } from 'mobx-react';
+import React from 'react';
+import { returnFalse, setupMoveUpEvents } from '../../../ClientUtils';
+import { emptyFunction } from '../../../Utils';
+import { Doc } from '../../../fields/Doc';
+import { StrCast } from '../../../fields/Types';
+import { undoable } from '../../util/UndoManager';
+import { ObservableReactComponent } from '../ObservableReactComponent';
+import { TagItem } from '../TagsView';
+import { DocumentView } from './DocumentView';
+import './IconTagBox.scss';
+
+export interface IconTagProps {
+ Views: DocumentView[];
+ IsEditing: boolean;
+}
+
+/**
+ * Renders the icon tags that rest under the document. The icons rendered are determined by the values of
+ * each icon in the userdoc.
+ */
+@observer
+export class IconTagBox extends ObservableReactComponent<IconTagProps> {
+ constructor(props: IconTagProps) {
+ super(props);
+ makeObservable(this);
+ }
+
+ @computed get View() { return this._props.Views.lastElement(); } // prettier-ignore
+ @computed get currentScale() { return this.View?.screenToLocalScale(); } // prettier-ignore
+
+ /**
+ * Sets or removes the specified tag
+ * @param tag tag name (should begin with '#')
+ * @param state flag to add or remove the metadata
+ */
+ setIconTag = undoable((tag: string, state: boolean) => {
+ this._props.Views.forEach(view => {
+ state && TagItem.addTagToDoc(view.dataDoc, tag);
+ !state && TagItem.removeTagFromDoc(view.dataDoc, tag);
+ });
+ }, 'toggle card tag');
+
+ /**
+ * Returns a renderable version of the button Doc that is colorized to indicate
+ * whether the doc has the associated tag set on it or not.
+ * @param doc doc to test
+ * @param key metadata icon button
+ * @returns an icon for the metdata button
+ */
+ getButtonIcon = (doc: Doc, key: Doc): JSX.Element => {
+ const icon = StrCast(key.icon) as IconProp;
+ const tag = StrCast(key.toolType);
+ const isActive = TagItem.docHasTag(doc, tag);
+ const color = isActive ? '#4476f7' : '#323232'; // TODO should use theme colors
+
+ return <FontAwesomeIcon icon={icon} style={{ color, height: '20px', width: '20px' }} />;
+ };
+
+ /**
+ * Renders the buttons to customize sorting depending on which group the card belongs to and the amount of total groups
+ */
+ render() {
+ const buttons = Doc.MyFilterHotKeys
+ .map(key => ({ key, tag: StrCast(key.toolType) }))
+ .filter(({ tag }) => this._props.IsEditing || TagItem.docHasTag(this.View.Document, tag) || (DocumentView.Selected.length === 1 && this.View.IsSelected))
+ .map(({ key, tag }) => (
+ <Tooltip key={tag} title={<div className="dash-tooltip">Click to add/remove this card from the {tag} group</div>}>
+ <button
+ type="button"
+ onPointerDown={e =>
+ setupMoveUpEvents(this, e, returnFalse, emptyFunction, clickEv => {
+ this.setIconTag(tag, !TagItem.docHasTag(this.View.Document, tag));
+ clickEv.stopPropagation();
+ })
+ }>
+ {this.getButtonIcon(this.View.Document, key)}
+ </button>
+ </Tooltip>
+ )); // prettier-ignore
+
+ return !buttons.length ? null : (
+ <div className="card-button-container" style={{ fontSize: '50px' }}>
+ {buttons}
+ </div>
+ );
+ }
+}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index d0a7fc6ac..aa4376bb2 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -11,7 +11,7 @@ import { DocData } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
import { ObjectField } from '../../../fields/ObjectField';
-import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types';
+import { Cast, ImageCast, NumCast, RTFCast, StrCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
import { TraceMobx } from '../../../fields/util';
import { emptyFunction } from '../../../Utils';
@@ -188,8 +188,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@undoBatch
setNativeSize = action(() => {
+ const oldnativeWidth = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']);
const nscale = NumCast(this._props.PanelWidth()) * NumCast(this.layoutDoc._freeform_scale, 1);
- const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']);
+ const nw = nscale / oldnativeWidth;
this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nw;
this.dataDoc[this.fieldKey + '_nativeWidth'] = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) * nw;
this.dataDoc._freeform_panX = nw * NumCast(this.dataDoc._freeform_panX);
@@ -198,6 +199,15 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this.dataDoc._freeform_panX_min = this.dataDoc._freeform_panX_min ? nw * NumCast(this.dataDoc._freeform_panX_min) : undefined;
this.dataDoc._freeform_panY_max = this.dataDoc._freeform_panY_max ? nw * NumCast(this.dataDoc._freeform_panY_max) : undefined;
this.dataDoc._freeform_panY_min = this.dataDoc._freeform_panY_min ? nw * NumCast(this.dataDoc._freeform_panY_min) : undefined;
+ const newnativeWidth = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']);
+ DocListCast(this.dataDoc[this.annotationKey]).forEach(doc => {
+ doc.x = (NumCast(doc.x) / oldnativeWidth) * newnativeWidth;
+ doc.y = (NumCast(doc.y) / oldnativeWidth) * newnativeWidth;
+ if (!RTFCast(doc[Doc.LayoutFieldKey(doc)])) {
+ doc.width = (NumCast(doc.width) / oldnativeWidth) * newnativeWidth;
+ doc.height = (NumCast(doc.height) / oldnativeWidth) * newnativeWidth;
+ }
+ });
});
@undoBatch
rotate = action(() => {
@@ -358,7 +368,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
TraceMobx();
const backColor = DashColor((this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string) ?? Colors.WHITE);
- const backAlpha = backColor.red() === 0 && backColor.green() === 0 && backColor.blue() === 0 ? backColor.alpha() : 1;
+ // allow use case where the image is transparent when the alpha value is to smallest possible value from UI (alpha = 1 out of 255)
+ const backAlpha = backColor.alpha() < 0.015 && backColor.alpha() > 0 ? backColor.alpha() : 1;
const srcpath = this.layoutDoc.hideImage ? '' : this.paths[0];
const fadepath = this.layoutDoc.hideImage ? '' : this.paths.lastElement();
const { nativeWidth, nativeHeight /* , nativeOrientation */ } = this.nativeSize;
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 95e344004..3daacc9bb 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -84,7 +84,7 @@ export class KeyValueBox extends ViewBoxBaseComponent<FieldViewProps>() {
const onDelegate = rawvalue.startsWith('=');
rawvalue = onDelegate ? rawvalue.substring(1) : rawvalue;
const type: 'computed' | 'script' | false = rawvalue.startsWith(':=') ? 'computed' : rawvalue.startsWith('$=') ? 'script' : false;
- rawvalue = type ? rawvalue.substring(2) : rawvalue;
+ rawvalue = type ? rawvalue.substring(2) : rawvalue.replace(/^:/, '');
rawvalue = rawvalue.replace(/.*\(\((.*)\)\)/, 'dashCallChat(_setCacheResult_, this, `$1`)');
const value = ["'", '"', '`'].includes(rawvalue.length ? rawvalue[0] : '') || !isNaN(+rawvalue) ? rawvalue : '`' + rawvalue + '`';
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 209c5abbc..42ac51107 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -56,10 +56,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@computed get pdfUrl() {
return Cast(this.dataDoc[this._props.fieldKey], PdfField);
}
- @computed get pdfThumb() {
- return ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url;
- }
-
constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
diff --git a/src/client/views/nodes/calendarBox/CalendarBox.scss b/src/client/views/nodes/calendarBox/CalendarBox.scss
new file mode 100644
index 000000000..f8ac4b2d1
--- /dev/null
+++ b/src/client/views/nodes/calendarBox/CalendarBox.scss
@@ -0,0 +1,25 @@
+.calendarBox {
+ display: flex;
+ width: 100%;
+ height: 100%;
+ transform-origin: top left;
+ .calendarBox-wrapper {
+ width: 100%;
+ height: 100%;
+ .fc-timegrid-body {
+ width: 100% !important;
+ table {
+ width: 100% !important;
+ }
+ }
+ .fc-col-header {
+ width: 100% !important;
+ }
+ .fc-daygrid-body {
+ width: 100% !important;
+ .fc-scrollgrid-sync-table {
+ width: 100% !important;
+ }
+ }
+ }
+}
diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx
index bd66941c3..678b7dd0b 100644
--- a/src/client/views/nodes/calendarBox/CalendarBox.tsx
+++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx
@@ -1,127 +1,207 @@
-import { Calendar, EventSourceInput } from '@fullcalendar/core';
+import { Calendar, DateInput, EventClickArg, EventSourceInput } from '@fullcalendar/core';
import dayGridPlugin from '@fullcalendar/daygrid';
import multiMonthPlugin from '@fullcalendar/multimonth';
-import { makeObservable } from 'mobx';
+import timeGrid from '@fullcalendar/timegrid';
+import interactionPlugin from '@fullcalendar/interaction';
+import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { dateRangeStrToDates } from '../../../../ClientUtils';
import { Doc } from '../../../../fields/Doc';
-import { StrCast } from '../../../../fields/Types';
-import { DocumentType } from '../../../documents/DocumentTypes';
-import { Docs } from '../../../documents/Documents';
-import { ViewBoxBaseComponent } from '../../DocComponent';
-import { FieldView, FieldViewProps } from '../FieldView';
-
-type CalendarView = 'month' | 'multi-month' | 'week';
+import { BoolCast, NumCast, StrCast } from '../../../../fields/Types';
+import { CollectionSubView, SubCollectionViewProps } from '../../collections/CollectionSubView';
+import './CalendarBox.scss';
+import { Id } from '../../../../fields/FieldSymbols';
+import { DocServer } from '../../../DocServer';
+import { DocumentView } from '../DocumentView';
+import { OpenWhere } from '../OpenWhere';
+import { DragManager } from '../../../util/DragManager';
+import { DocData } from '../../../../fields/DocSymbols';
+
+type CalendarView = 'multiMonth' | 'dayGridMonth' | 'timeGridWeek' | 'timeGridDay';
@observer
-export class CalendarBox extends ViewBoxBaseComponent<FieldViewProps>() {
- public static LayoutString(fieldKey: string = 'calendar') {
- return FieldView.LayoutString(CalendarBox, fieldKey);
- }
-
- constructor(props: FieldViewProps) {
+export class CalendarBox extends CollectionSubView() {
+ _calendarRef: HTMLDivElement | null = null;
+ _calendar: Calendar | undefined;
+ _oldWheel: HTMLElement | null = null;
+ _observer: ResizeObserver | undefined;
+ _eventsDisposer: IReactionDisposer | undefined;
+ _selectDisposer: IReactionDisposer | undefined;
+
+ constructor(props: SubCollectionViewProps) {
super(props);
makeObservable(this);
}
- componentDidMount(): void {}
-
- componentWillUnmount(): void {}
-
- _calendarRef = React.createRef<HTMLElement>();
+ @observable _multiMonth = 0;
+ isMultiMonth: boolean | undefined;
- get dateRangeStr() {
- return StrCast(this.Document.date_range);
+ componentDidMount(): void {
+ this._props.setContentViewBox?.(this);
+ this._eventsDisposer = reaction(
+ () => ({ events: this.calendarEvents }),
+ ({ events }) => this._calendar?.setOption('events', events),
+ { fireImmediately: true }
+ );
+ this._selectDisposer = reaction(
+ () => ({ initialDate: this.dateSelect }),
+ ({ initialDate }) => {
+ const state = this._calendar?.getCurrentData();
+ state &&
+ this._calendar?.dispatch({
+ type: 'CHANGE_DATE',
+ dateMarker: state.dateEnv.createMarker(initialDate.start),
+ });
+ setTimeout(() => (initialDate.start.toISOString() !== initialDate.end.toISOString() ? this._calendar?.select(initialDate.start, initialDate.end) : this._calendar?.select(initialDate.start)));
+ },
+ { fireImmediately: true }
+ );
}
-
- // Choose a calendar view based on the date range
- get calendarViewType(): CalendarView {
- const [fromDate, toDate] = dateRangeStrToDates(this.dateRangeStr);
-
- if (fromDate.getFullYear() !== toDate.getFullYear() || fromDate.getMonth() !== toDate.getMonth()) return 'multi-month';
-
- if (Math.abs(fromDate.getDay() - toDate.getDay()) > 7) return 'month';
- return 'week';
+ componentWillUnmount(): void {
+ this._eventsDisposer?.();
+ this._selectDisposer?.();
}
- get calendarStartDate() {
- return this.dateRangeStr.split('|')[0];
+ @computed get calendarEvents(): EventSourceInput | undefined {
+ return this.childDocs.map(doc => {
+ const { start, end } = dateRangeStrToDates(StrCast(doc.date_range));
+ return {
+ title: StrCast(doc.title),
+ start,
+ end,
+ groupId: doc[Id],
+ startEditable: true,
+ endEditable: true,
+ allDay: BoolCast(doc.allDay),
+ classNames: ['mother'], // will determine the style
+ editable: true, // subject to change in the future
+ backgroundColor: this.eventToColor(doc),
+ borderColor: this.eventToColor(doc),
+ color: 'white',
+ extendedProps: {
+ description: StrCast(doc.description),
+ },
+ };
+ });
}
- get calendarToDate() {
- return this.dateRangeStr.split('|')[1];
+ @computed get dateRangeStrDates() {
+ return dateRangeStrToDates(StrCast(this.Document.date_range));
}
-
- get childDocs(): Doc[] {
- return this.childDocs; // get all sub docs for a calendar
+ get dateSelect() {
+ return dateRangeStrToDates(StrCast(this.Document.date));
}
- docBackgroundColor(type: string): string {
- // TODO: Return a different color based on the event type
- console.log(type);
- return 'blue';
+ // Choose a calendar view based on the date range
+ @computed get calendarViewType(): CalendarView {
+ if (this.dataDoc[this.fieldKey + '_calendarType']) return StrCast(this.dataDoc[this.fieldKey + '_calendarType']) as CalendarView;
+ if (this.isMultiMonth) return 'multiMonth';
+ const { start, end } = this.dateRangeStrDates;
+ if (start.getFullYear() !== end.getFullYear() || start.getMonth() !== end.getMonth()) return 'multiMonth';
+ if (Math.abs(start.getDay() - end.getDay()) > 7) return 'dayGridMonth';
+ return 'timeGridWeek';
}
- get calendarEvents(): EventSourceInput | undefined {
- if (this.childDocs.length === 0) return undefined;
- return this.childDocs.map(doc => {
- const docTitle = StrCast(doc.title);
- const docDateRange = StrCast(doc.date_range);
- const [startDate, endDate] = dateRangeStrToDates(docDateRange);
- const docType = doc.type;
- const docDescription = doc.description ? StrCast(doc.description) : '';
+ // TODO: Return a different color based on the event type
+ eventToColor(event: Doc): string {
+ return 'red';
+ }
- return {
- title: docTitle,
- start: startDate,
- end: endDate,
- allDay: false,
- classNames: [StrCast(docType)], // will determine the style
- editable: false, // subject to change in the future
- backgroundColor: this.docBackgroundColor(StrCast(doc.type)),
- color: 'white',
- extendedProps: {
- description: docDescription,
- },
- };
+ internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData) {
+ if (!super.onInternalDrop(e, de)) return false;
+ de.complete.docDragData?.droppedDocuments.forEach(doc => {
+ const today = new Date().toISOString();
+ if (!doc.date_range) doc[DocData].date_range = `${today}|${today}`;
});
+ return true;
}
- handleEventClick = (/* arg: EventClickArg */) => {
- // TODO: open popover with event description, option to open CalendarManager and change event date, delete event, etc.
+ onInternalDrop = (e: Event, de: DragManager.DropEvent): boolean => {
+ if (de.complete.docDragData?.droppedDocuments.length) return this.internalDocDrop(e, de, de.complete.docDragData);
+ return false;
};
- calendarEl: HTMLElement = document.getElementById('calendar-box-v1')!;
+ handleEventClick = (arg: EventClickArg) => {
+ const doc = DocServer.GetCachedRefField(arg.event._def.groupId ?? '');
+ DocumentView.DeselectAll();
+ if (doc) {
+ DocumentView.showDocument(doc, { openLocation: OpenWhere.lightboxAlways });
+ arg.jsEvent.stopPropagation();
+ }
+ };
// https://fullcalendar.io
- get calendar() {
- return new Calendar(this.calendarEl, {
- plugins: [this.calendarViewType === 'multi-month' ? multiMonthPlugin : dayGridPlugin],
- headerToolbar: {
- left: 'prev,next today',
- center: 'title',
- right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek',
- },
- initialDate: this.calendarStartDate,
- navLinks: true,
- editable: false,
- displayEventTime: false,
- displayEventEnd: false,
- events: this.calendarEvents,
- eventClick: this.handleEventClick,
- });
- }
+ renderCalendar = () => {
+ const cal = !this._calendarRef
+ ? null
+ : (this._calendar = new Calendar(this._calendarRef, {
+ plugins: [multiMonthPlugin, dayGridPlugin, timeGrid, interactionPlugin],
+ headerToolbar: {
+ left: 'prev,next today',
+ center: 'title',
+ right: 'multiMonth dayGridMonth timeGridWeek timeGridDay',
+ },
+ selectable: true,
+ initialView: this.calendarViewType === 'multiMonth' ? undefined : this.calendarViewType,
+ initialDate: this.dateSelect.start,
+ navLinks: true,
+ editable: false,
+ displayEventTime: false,
+ displayEventEnd: false,
+ select: info => {
+ const start = dateRangeStrToDates(info.startStr).start.toISOString();
+ const end = dateRangeStrToDates(info.endStr).start.toISOString();
+ this.dataDoc.date = start + '|' + end;
+ },
+ aspectRatio: NumCast(this.Document.width) / NumCast(this.Document.height),
+ events: this.calendarEvents,
+ eventClick: this.handleEventClick,
+ }));
+ cal?.render();
+ setTimeout(() => cal?.view.calendar.select(this.dateSelect.start, this.dateSelect.end));
+ };
+ onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
render() {
return (
- <div className="calendar-box-conatiner">
- <div id="calendar-box-v1" />
+ <div
+ key={this.calendarViewType}
+ className="calendarBox"
+ onPointerDown={e => {
+ setTimeout(
+ action(() => {
+ const cname = (e.nativeEvent.target as HTMLButtonElement)?.className ?? '';
+ if (cname.includes('multiMonth')) this.dataDoc[this.fieldKey + '_calendarType'] = 'multiMonth';
+ if (cname.includes('dayGridMonth')) this.dataDoc[this.fieldKey + '_calendarType'] = 'dayGridMonth';
+ if (cname.includes('timeGridWeek')) this.dataDoc[this.fieldKey + '_calendarType'] = 'timeGridWeek';
+ if (cname.includes('timeGridDay')) this.dataDoc[this.fieldKey + '_calendarType'] = 'timeGridDay';
+ })
+ );
+ }}
+ style={{
+ width: this._props.PanelWidth() / this._props.ScreenToLocalTransform().Scale,
+ height: this._props.PanelHeight() / this._props.ScreenToLocalTransform().Scale,
+ transform: `scale(${this._props.ScreenToLocalTransform().Scale})`,
+ }}
+ ref={r => {
+ this.createDashEventsTarget(r);
+ this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
+ this._oldWheel = r;
+ // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
+ r?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+
+ if (r) {
+ this._observer?.disconnect();
+ (this._observer = new ResizeObserver(() => {
+ this._calendar?.setOption('aspectRatio', NumCast(this.Document.width) / NumCast(this.Document.height));
+ this._calendar?.updateSize();
+ })).observe(r);
+ this.renderCalendar();
+ }
+ }}>
+ <div className="calendarBox-wrapper" ref={r => (this._calendarRef = r)} />
</div>
);
}
}
-Docs.Prototypes.TemplateMap.set(DocumentType.CALENDAR, {
- layout: { view: CalendarBox, dataField: 'data' },
- options: { acl: '' },
-});
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 996c6843e..84d3fc748 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -283,6 +283,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
ele.append(contents);
}
this._selectionHTML = ele?.innerHTML;
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
/* empty */
}
@@ -569,7 +570,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const draggedDoc = dragData.droppedDocuments.lastElement();
let added: Opt<boolean>;
const dropAction = dragData.dropAction || dragData.userDropAction;
- if ([AclEdit, AclAdmin, AclSelfEdit].includes(effectiveAcl)) {
+ if ([AclEdit, AclAdmin, AclSelfEdit].includes(effectiveAcl) && !dragData.draggedDocuments.includes(this.Document)) {
// replace text contents when dragging with Alt
if (de.altKey) {
const fieldKey = Doc.LayoutFieldKey(draggedDoc);
@@ -2043,7 +2044,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
style={{
cursor: this._props.isContentActive() ? 'text' : undefined,
height: this._props.height ? 'max-content' : undefined,
- overflow: this.layout_autoHeight ? 'hidden' : undefined,
pointerEvents: Doc.ActiveTool === InkTool.None && !SnappingManager.ExploreMode ? undefined : 'none',
}}
onContextMenu={this.specificContextMenu}
@@ -2062,7 +2062,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}}
style={{
width: this.noSidebar ? '100%' : `calc(100% - ${this.layout_sidebarWidthPercent})`,
- overflow: this.layoutDoc._createDocOnCR ? 'hidden' : this.layoutDoc._layout_autoHeight ? 'visible' : undefined,
+ overflow: this.layoutDoc._createDocOnCR || this.layoutDoc._layout_hideScroll ? 'hidden' : this.layout_autoHeight ? 'visible' : undefined,
}}
onScroll={this.onScroll}
onDrop={this.ondrop}>
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index e0d6c7c05..f58434906 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -404,9 +404,9 @@ export class RichTextRules {
if (!tags.includes(tag)) {
tags.push(tag);
this.Document[DocData].tags = new List<string>(tags);
- this.Document[DocData].showTags = true;
+ this.Document._layout_showTags = true;
}
- const fieldView = state.schema.nodes.dashField.create({ fieldKey: '#' + tag });
+ const fieldView = state.schema.nodes.dashField.create({ fieldKey: tag.startsWith('@') ? tag.replace(/^@/, '') : '#' + tag });
return state.tr
.setSelection(new TextSelection(state.doc.resolve(start), state.doc.resolve(end)))
.replaceSelectionWith(fieldView, true)
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.scss b/src/client/views/pdf/GPTPopup/GPTPopup.scss
index 6d8793f82..0247dc10c 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.scss
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.scss
@@ -7,10 +7,13 @@ $highlightedText: #82e0ff;
.summary-box {
position: fixed;
- bottom: 10px;
- right: 10px;
+ top: 115px;
+ left: 75px;
width: 250px;
+ height: 200px;
min-height: 200px;
+ min-width: 180px;
+
border-radius: 16px;
padding: 16px;
padding-bottom: 0;
@@ -21,6 +24,18 @@ $highlightedText: #82e0ff;
background-color: #ffffff;
box-shadow: 0 2px 5px #7474748d;
color: $textgrey;
+ resize: both; /* Allows resizing */
+ overflow: auto;
+
+ .resize-handle {
+ width: 10px;
+ height: 10px;
+ background: #ccc;
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ cursor: se-resize;
+ }
.summary-heading {
display: flex;
@@ -51,25 +66,76 @@ $highlightedText: #82e0ff;
.content-wrapper {
padding-top: 10px;
min-height: 50px;
- max-height: 150px;
+ // max-height: 150px;
overflow-y: auto;
+ height: 100%
}
.btns-wrapper-gpt {
- height: 50px;
+ height: 100%;
display: flex;
justify-content: center;
align-items: center;
- transform: translateY(30px);
+ flex-direction: column;
+
+ .inputWrapper{
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 60px;
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ background-color: white;
+
+ }
.searchBox-input{
- transform: translateY(-15px);
- height: 50px;
+ height: 40px;
border-radius: 10px;
+ position: absolute;
+ bottom: 10px;
border-color: #5b97ff;
+ width: 90%
}
+ .chat-wrapper {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ max-height: calc(100vh - 80px);
+ overflow-y: auto;
+ padding-bottom: 60px;
+ }
+
+ .chat-bubbles {
+ margin-top: 20px;
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ }
+
+ .chat-bubble {
+ padding: 10px;
+ margin-bottom: 10px;
+ border-radius: 10px;
+ max-width: 60%;
+ }
+
+ .user-message {
+ background-color: #283d53;
+ align-self: flex-end;
+ color: whitesmoke;
+ }
+
+ .chat-message {
+ background-color: #367ae7;
+ align-self: flex-start;
+ color:whitesmoke;
+ }
+
+
.summarizing {
@@ -78,16 +144,14 @@ $highlightedText: #82e0ff;
}
- }
- button {
- font-size: 9px;
- padding: 10px;
- color: #ffffff;
- background-color: $button;
- border-radius: 5px;
+
+
+
}
+
+
.text-btn {
&:hover {
background-color: $button;
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index a37e73e27..d5f5f620c 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -3,7 +3,7 @@ import { Button, IconButton, Type } from 'browndash-components';
import { action, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { CgClose } from 'react-icons/cg';
+import { CgClose, CgCornerUpLeft } from 'react-icons/cg';
import ReactLoading from 'react-loading';
import { TypeAnimation } from 'react-type-animation';
import { ClientUtils } from '../../../../ClientUtils';
@@ -11,13 +11,14 @@ import { Doc } from '../../../../fields/Doc';
import { NumCast, StrCast } from '../../../../fields/Types';
import { Networking } from '../../../Network';
import { GPTCallType, gptAPICall, gptImageCall } from '../../../apis/gpt/GPT';
-import { Docs } from '../../../documents/Documents';
import { DocUtils } from '../../../documents/DocUtils';
+import { Docs } from '../../../documents/Documents';
+import { SettingsManager } from '../../../util/SettingsManager';
+import { SnappingManager } from '../../../util/SnappingManager';
import { ObservableReactComponent } from '../../ObservableReactComponent';
+import { DocumentView } from '../../nodes/DocumentView';
import { AnchorMenu } from '../AnchorMenu';
import './GPTPopup.scss';
-import { SettingsManager } from '../../../util/SettingsManager';
-import { SnappingManager } from '../../../util/SnappingManager';
export enum GPTPopupMode {
SUMMARY,
@@ -25,7 +26,15 @@ export enum GPTPopupMode {
IMAGE,
FLASHCARD,
DATA,
+ CARD,
SORT,
+ QUIZ,
+}
+
+export enum GPTQuizType {
+ CURRENT = 0,
+ CHOOSE = 1,
+ MULTIPLE = 2,
}
interface GPTPopupProps {}
@@ -34,6 +43,8 @@ interface GPTPopupProps {}
export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
// eslint-disable-next-line no-use-before-define
static Instance: GPTPopup;
+ private messagesEndRef: React.RefObject<HTMLDivElement>;
+
@observable private chatMode: boolean = false;
private correlatedColumns: string[] = [];
@@ -63,7 +74,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
};
@observable
public dataJson: string = '';
- public dataChatPrompt: string | null = null;
+ public dataChatPrompt: string | undefined = undefined;
@action
public setDataJson = (text: string) => {
if (text === '') this.dataChatPrompt = '';
@@ -140,7 +151,8 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
this.sortDesc = t;
};
- @observable onSortComplete?: (sortResult: string) => void;
+ @observable onSortComplete?: (sortResult: string, questionType: string, tag?: string) => void;
+ @observable onQuizRandom?: () => void;
@observable cardsDoneLoading = false;
@action setCardsDoneLoading(done: boolean) {
@@ -148,22 +160,157 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
this.cardsDoneLoading = done;
}
+ @observable sortRespText: string = '';
+
+ @action setSortRespText(resp: string) {
+ this.sortRespText = resp;
+ }
+
+ @observable chatSortPrompt: string = '';
+
+ sortPromptChanged = action((e: React.ChangeEvent<HTMLInputElement>) => {
+ this.chatSortPrompt = e.target.value;
+ });
+
+ @observable quizAnswer: string = '';
+
+ quizAnswerChanged = action((e: React.ChangeEvent<HTMLInputElement>) => {
+ this.quizAnswer = e.target.value;
+ });
+
+ @observable conversationArray: string[] = ['Hi! In this pop up, you can ask ChatGPT questions about your documents and filter / sort them. '];
+
+ /**
+ * When the cards are in quiz mode in the card view, allows gpt to determine whether the user's answer was correct
+ * @returns
+ */
+ generateQuiz = async () => {
+ this.setLoading(true);
+ this.setSortDone(false);
+
+ const quizType = this.quizMode;
+
+ const selected = DocumentView.SelectedDocs().lastElement();
+
+ const questionText = 'Question: ' + StrCast(selected['gptInputText']);
+
+ if (StrCast(selected['gptRubric']) === '') {
+ const rubricText = 'Rubric: ' + (await this.generateRubric(StrCast(selected['gptInputText']), selected));
+ }
+
+ const rubricText = 'Rubric: ' + StrCast(selected['gptRubric']);
+ const queryText = questionText + ' UserAnswer: ' + this.quizAnswer + '. ' + 'Rubric' + rubricText;
+
+ try {
+ const res = await gptAPICall(queryText, GPTCallType.QUIZ);
+ if (!res) {
+ console.error('GPT call failed');
+ return;
+ }
+ console.log(res);
+ this.setQuizResp(res);
+ this.conversationArray.push(res);
+
+ this.setLoading(false);
+ this.setSortDone(true);
+ } catch (err) {
+ console.error('GPT call failed');
+ }
+
+ if (this.onQuizRandom) {
+ this.onQuizRandom();
+ }
+ };
+
+ /**
+ * Generates a rubric by which to compare the user's answer to
+ * @param inputText user's answer
+ * @param doc the doc the user is providing info about
+ * @returns gpt's response
+ */
+ generateRubric = async (inputText: string, doc: Doc) => {
+ try {
+ const res = await gptAPICall(inputText, GPTCallType.RUBRIC);
+ doc['gptRubric'] = res;
+ return res;
+ } catch (err) {
+ console.error('GPT call failed');
+ }
+ };
+
+ @observable private regenerateCallback: (() => Promise<void>) | null = null;
+
+ /**
+ * Callback function that causes the card view to update the childpair string list
+ * @param callback
+ */
+ @action public setRegenerateCallback(callback: () => Promise<void>) {
+ this.regenerateCallback = callback;
+ }
+
public addDoc: (doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean = () => false;
public createFilteredDoc: (axes?: string[]) => boolean = () => false;
public addToCollection: ((doc: Doc | Doc[], annotationKey?: string | undefined) => boolean) | undefined;
+ @observable quizRespText: string = '';
+
+ @action setQuizResp(resp: string) {
+ this.quizRespText = resp;
+ }
+
/**
- * Sorts cards in the CollectionCardDeckView
+ * Generates a response to the user's question depending on the type of their question
*/
- generateSort = async () => {
+ generateCard = async () => {
+ console.log(this.chatSortPrompt + 'USER PROMPT');
this.setLoading(true);
this.setSortDone(false);
+ if (this.regenerateCallback) {
+ await this.regenerateCallback();
+ }
+
try {
- const res = await gptAPICall(this.sortDesc, GPTCallType.SORT);
+ // const res = await gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
+ const questionType = await gptAPICall(this.chatSortPrompt, GPTCallType.TYPE);
+ const questionNumber = questionType.split(' ')[0];
+ console.log(questionType);
+ let res = '';
+
+ switch (questionNumber) {
+ case '1':
+ case '2':
+ case '4':
+ res = await gptAPICall(this.sortDesc, GPTCallType.SUBSET, this.chatSortPrompt);
+ break;
+ case '6':
+ res = await gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
+ break;
+ default:
+ const selected = DocumentView.SelectedDocs().lastElement();
+ const questionText = StrCast(selected!['gptInputText']);
+
+ res = await gptAPICall(questionText, GPTCallType.INFO, this.chatSortPrompt);
+ break;
+ }
+
// Trigger the callback with the result
if (this.onSortComplete) {
- this.onSortComplete(res || 'Something went wrong :(');
+ this.onSortComplete(res || 'Something went wrong :(', questionNumber, questionType.split(' ').slice(1).join(' '));
+
+ let explanation = res;
+
+ if (questionType != '5' && questionType != '3') {
+ // Extract explanation surrounded by ------ at the top or both at the top and bottom
+ const explanationMatch = res.match(/------\s*([\s\S]*?)\s*(?:------|$)/) || [];
+ explanation = explanationMatch[1] ? explanationMatch[1].trim() : 'No explanation found';
+ }
+
+ // Set the extracted explanation to sortRespText
+ this.setSortRespText(explanation);
+ this.conversationArray.push(this.sortRespText);
+ this.scrollToBottom();
+
console.log(res);
}
} catch (err) {
@@ -305,67 +452,143 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
super(props);
makeObservable(this);
GPTPopup.Instance = this;
+ this.messagesEndRef = React.createRef();
}
+ scrollToBottom = () => {
+ setTimeout(() => {
+ // Code to execute after 1 second (1000 ms)
+ if (this.messagesEndRef.current) {
+ this.messagesEndRef.current.scrollIntoView({ behavior: 'smooth', block: 'end' });
+ }
+ }, 50);
+ };
+
componentDidUpdate = () => {
if (this.loading) {
this.setDone(false);
}
};
+ @observable quizMode: GPTQuizType = GPTQuizType.CURRENT;
+ @action setQuizMode(g: GPTQuizType) {
+ this.quizMode = g;
+ }
+
+ cardMenu = () => (
+ <div className="btns-wrapper-gpt">
+ <Button
+ tooltip="Have ChatGPT sort, tag, define, or filter your cards for you!"
+ text="Modify/Sort Cards!"
+ onClick={() => this.setMode(GPTPopupMode.SORT)}
+ color={StrCast(Doc.UserDoc().userVariantColor)}
+ type={Type.TERT}
+ style={{
+ width: '100%',
+ height: '40%',
+ textAlign: 'center',
+ color: '#ffffff',
+ fontSize: '16px',
+ marginBottom: '10px',
+ }}
+ />
+ <Button
+ tooltip="Test your knowledge with ChatGPT!"
+ text="Quiz Cards!"
+ onClick={() => {
+ this.conversationArray = ['Define the selected card!'];
+ this.setMode(GPTPopupMode.QUIZ);
+ if (this.onQuizRandom) {
+ this.onQuizRandom();
+ }
+ }}
+ color={StrCast(Doc.UserDoc().userVariantColor)}
+ type={Type.TERT}
+ style={{
+ width: '100%',
+ textAlign: 'center',
+ color: '#ffffff',
+ fontSize: '16px',
+ height: '40%',
+ }}
+ />
+ </div>
+ );
+
+ handleKeyPress = async (e: React.KeyboardEvent, isSort: boolean) => {
+ if (e.key === 'Enter') {
+ e.stopPropagation();
+
+ if (isSort) {
+ this.conversationArray.push(this.chatSortPrompt);
+ await this.generateCard();
+ this.chatSortPrompt = '';
+ } else {
+ this.conversationArray.push(this.quizAnswer);
+ await this.generateQuiz();
+ this.quizAnswer = '';
+ }
+
+ this.scrollToBottom();
+ }
+ };
+
+ cardActual = (opt: GPTPopupMode) => {
+ const isSort = opt === GPTPopupMode.SORT;
+ return (
+ <div className="btns-wrapper-gpt">
+ <div className="chat-wrapper">
+ <div className="chat-bubbles">
+ {this.conversationArray.map((message, index) => (
+ <div key={index} className={`chat-bubble ${index % 2 === 1 ? 'user-message' : 'chat-message'}`}>
+ {message}
+ </div>
+ ))}
+ {(!this.cardsDoneLoading || this.loading) && <div className={`chat-bubble chat-message`}>...</div>}
+ </div>
+
+ <div ref={this.messagesEndRef} style={{ height: '100px' }} />
+ </div>
+
+ <div className="inputWrapper">
+ <input
+ className="searchBox-input"
+ defaultValue=""
+ value={isSort ? this.chatSortPrompt : this.quizAnswer} // Controlled input
+ autoComplete="off"
+ onChange={isSort ? this.sortPromptChanged : this.quizAnswerChanged}
+ onKeyDown={e => {
+ this.handleKeyPress(e, isSort);
+ }}
+ type="text"
+ placeholder={`${isSort ? 'Have ChatGPT sort, tag, define, or filter your cards for you!' : 'Define the selected card!'}`}
+ />
+ </div>
+ </div>
+ );
+ };
+
sortBox = () => (
- <>
- <div>
- {this.heading('SORTING')}
- {this.loading ? (
+ <div style={{ height: '80%' }}>
+ {this.heading(this.mode === GPTPopupMode.SORT ? 'SORTING' : 'QUIZ')}
+ <>
+ {!this.cardsDoneLoading ? (
<div className="content-wrapper">
<div className="loading-spinner">
<ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
- <span>Loading...</span>
+ {this.loading ? <span>Loading...</span> : <span>Reading Cards...</span>}
</div>
</div>
+ ) : this.mode === GPTPopupMode.CARD ? (
+ this.cardMenu()
) : (
- <>
- {!this.cardsDoneLoading ? (
- <div className="content-wrapper">
- <div className="loading-spinner">
- <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
- <span>Reading Cards...</span>
- </div>
- </div>
- ) : (
- !this.sortDone && (
- <div className="btns-wrapper-gpt">
- <Button
- tooltip="Have ChatGPT sort your cards for you!"
- text="Sort!"
- onClick={this.generateSort}
- color={StrCast(Doc.UserDoc().userVariantColor)}
- type={Type.TERT}
- style={{
- width: '90%', // Almost as wide as the container
- textAlign: 'center',
- color: '#ffffff', // White text
- fontSize: '16px', // Adjust font size as needed
- }}
- />
- </div>
- )
- )}
-
- {this.sortDone && (
- <div>
- <div className="content-wrapper">
- <p>{this.text === 'Something went wrong :(' ? 'Something went wrong :(' : 'Sorting done! Feel free to move things around / regenerate :) !'}</p>
- <IconButton tooltip="Generate Again" onClick={() => this.setSortDone(false)} icon={<FontAwesomeIcon icon="redo-alt" size="lg" />} color={StrCast(Doc.UserDoc().userVariantColor)} />
- </div>
- </div>
- )}
- </>
- )}
- </div>
- </>
+ this.cardActual(this.mode)
+ ) // Call the functions to render JSX
+ }
+ </>
+ </div>
);
+
imageBox = () => (
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
{this.heading('GENERATED IMAGE')}
@@ -511,14 +734,52 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
heading = (headingText: string) => (
<div className="summary-heading">
<label className="summary-text">{headingText}</label>
- {this.loading ? <ReactLoading type="spin" color="#bcbcbc" width={14} height={14} /> : <IconButton color={StrCast(SettingsManager.userVariantColor)} tooltip="close" icon={<CgClose size="16px" />} onClick={() => this.setVisible(false)} />}
+ {this.loading ? (
+ <ReactLoading type="spin" color="#bcbcbc" width={14} height={14} />
+ ) : (
+ <>
+ {(this.mode === GPTPopupMode.SORT || this.mode === GPTPopupMode.QUIZ) && (
+ <IconButton color={StrCast(SettingsManager.userVariantColor)} tooltip="back" icon={<CgCornerUpLeft size="16px" />} onClick={() => (this.mode = GPTPopupMode.CARD)} style={{ right: '50px', position: 'absolute' }} />
+ )}
+ <IconButton
+ color={StrCast(SettingsManager.userVariantColor)}
+ tooltip="close"
+ icon={<CgClose size="16px" />}
+ onClick={() => {
+ this.setVisible(false);
+ }}
+ />
+ </>
+ )}
</div>
);
render() {
+ let content;
+
+ switch (this.mode) {
+ case GPTPopupMode.SUMMARY:
+ content = this.summaryBox();
+ break;
+ case GPTPopupMode.DATA:
+ content = this.dataAnalysisBox();
+ break;
+ case GPTPopupMode.IMAGE:
+ content = this.imageBox();
+ break;
+ case GPTPopupMode.SORT:
+ case GPTPopupMode.CARD:
+ case GPTPopupMode.QUIZ:
+ content = this.sortBox();
+ break;
+ default:
+ content = null;
+ }
+
return (
<div className="summary-box" style={{ display: this.visible ? 'flex' : 'none' }}>
- {this.mode === GPTPopupMode.SUMMARY ? this.summaryBox() : this.mode === GPTPopupMode.DATA ? this.dataAnalysisBox() : this.mode === GPTPopupMode.IMAGE ? this.imageBox() : this.mode === GPTPopupMode.SORT ? this.sortBox() : null}
+ {content}
+ <div className="resize-handle" />
</div>
);
}
diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx
index 4f6f5d314..6f70e96ab 100644
--- a/src/client/views/search/FaceRecognitionHandler.tsx
+++ b/src/client/views/search/FaceRecognitionHandler.tsx
@@ -30,6 +30,7 @@ import { DocumentManager } from '../../util/DocumentManager';
* face_annos - a list of face annotations, where each anno has
*/
export class FaceRecognitionHandler {
+ // eslint-disable-next-line no-use-before-define
static _instance: FaceRecognitionHandler;
private _apiModelReady = false;
private _pendingAPIModelReadyDocs: Doc[] = [];
@@ -119,8 +120,7 @@ export class FaceRecognitionHandler {
* @param faceDoc - unique face Doc
*/
public static UniqueFaceRemoveFaceImage = (faceAnno: Doc, faceDoc: Doc) => {
- Doc.RemoveDocFromList(faceDoc[DocData], 'face_annos', faceAnno);
- faceAnno.face = undefined;
+ FaceRecognitionHandler.ImageDocFaceAnnos(faceAnno).forEach(face => Doc.RemoveDocFromList(faceDoc[DocData], 'face_annos', face) && (face.face = undefined));
};
constructor() {
@@ -221,7 +221,8 @@ export class FaceRecognitionHandler {
.then(imgDocFaceDescriptions => { // For each face detected, find a match.
const annos = [] as Doc[];
const scale = NumCast(imgDoc.data_nativeWidth) / img.width;
- imgDocFaceDescriptions.forEach((fd, i) => {
+ const showTags= imgDocFaceDescriptions.length > 1;
+ imgDocFaceDescriptions.forEach(fd => {
const faceDescriptor = new List<number>(Array.from(fd.descriptor));
const matchedUniqueFace = this.findMatchingFaceDoc(fd.descriptor) ?? this.createUniqueFaceDoc(activeDashboard);
const faceAnno = Docs.Create.FreeformDocument([], {
@@ -234,12 +235,14 @@ export class FaceRecognitionHandler {
y: fd.alignedRect.box.top * scale,
_width: fd.alignedRect.box.width * scale,
_height: fd.alignedRect.box.height * scale,
+ _layout_showTags: showTags
})
FaceRecognitionHandler.UniqueFaceAddFaceImage(faceAnno, matchedUniqueFace); // add image/faceDescriptor to matched unique face
annos.push(faceAnno);
});
imgDoc[DocData].data_annotations = new List<Doc>(annos);
+ imgDoc._layout_showTags = annos.length > 0;
return imgDocFaceDescriptions;
})
); // prettier-ignore
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index e7d6a9460..b3a17de8f 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -258,7 +258,13 @@ export class Doc extends RefField {
public static set ActivePresentation(val) { Doc.ActiveDashboard && (Doc.ActiveDashboard.activePresentation = val) } // prettier-ignore
public static get ActiveDashboard() { return DocCast(Doc.UserDoc().activeDashboard); } // prettier-ignore
public static set ActiveDashboard(val: Opt<Doc>) { Doc.UserDoc().activeDashboard = val; } // prettier-ignore
-
+ public static get MyFilterHotKeys() { return DocListCast(DocCast(DocCast(Doc.UserDoc().myContextMenuBtns)?.Filter)?.data).filter(key => key.toolType !== "-opts-"); } // prettier-ignore
+ public static RemFromFilterHotKeys(doc: Doc) {
+ return Doc.RemoveDocFromList(DocCast(DocCast(Doc.UserDoc().myContextMenuBtns)?.Filter), 'data', doc);
+ }
+ public static AddToFilterHotKeys(doc: Doc) {
+ return Doc.AddDocToList(DocCast(DocCast(Doc.UserDoc().myContextMenuBtns)?.Filter), 'data', doc);
+ }
public static IsInMyOverlay(doc: Doc) { return Doc.MyOverlayDocs.includes(doc); } // prettier-ignore
public static AddToMyOverlay(doc: Doc) { return Doc.ActiveDashboard ? Doc.AddDocToList(Doc.ActiveDashboard, 'myOverlayDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore
public static RemFromMyOverlay(doc: Doc) { return Doc.ActiveDashboard ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myOverlayDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore
diff --git a/src/server/ApiManagers/SearchManager.ts b/src/server/ApiManagers/SearchManager.ts
deleted file mode 100644
index 684b49eaf..000000000
--- a/src/server/ApiManagers/SearchManager.ts
+++ /dev/null
@@ -1,200 +0,0 @@
-/* eslint-disable no-use-before-define */
-import { exec } from 'child_process';
-import { cyan, green, red, yellow } from 'colors';
-import { logExecution } from '../ActionUtilities';
-import { Method } from '../RouteManager';
-import RouteSubscriber from '../RouteSubscriber';
-import { Search } from '../Search';
-import { Database } from '../database';
-import ApiManager, { Registration } from './ApiManager';
-
-export class SearchManager extends ApiManager {
- protected initialize(register: Registration): void {
- register({
- method: Method.GET,
- subscription: new RouteSubscriber('solr').add('action'),
- secureHandler: async ({ req, res }) => {
- const { action } = req.params;
- switch (action) {
- case 'start':
- case 'stop':
- {
- const status = req.params.action === 'start';
- SolrManager.SetRunning(status);
- }
- break;
- case 'update':
- await SolrManager.update();
- break;
- default:
- console.log(yellow(`${action} is an unknown solr operation.`));
- }
- res.redirect('/home');
- },
- });
-
- register({
- method: Method.GET,
- subscription: '/dashsearch',
- secureHandler: async ({ req, res }) => {
- const solrQuery: any = {};
- ['q', 'fq', 'start', 'rows', 'sort', 'hl.maxAnalyzedChars', 'hl', 'hl.fl'].forEach(key => {
- solrQuery[key] = req.query[key];
- });
- if (solrQuery.q === undefined) {
- res.send([]);
- return;
- }
- const results = await Search.search(solrQuery);
- res.send(results);
- },
- });
- }
-}
-
-export namespace SolrManager {
- export function SetRunning(status: boolean) {
- const args = status ? 'start' : 'stop -p 8983';
- console.log(`solr management: trying to ${args}`);
- exec(`solr ${args}`, { cwd: './solr-8.3.1/bin' }, (error, stdout, stderr) => {
- if (error) {
- console.log(red(`solr management error: unable to ${args} server`));
- console.log(red(error.message));
- }
- console.log(cyan(stdout));
- console.log(yellow(stderr));
- });
- if (status) {
- console.log(cyan('Start script is executing: please allow 15 seconds for solr to start on port 8983.'));
- }
- }
-
- export async function update() {
- console.log(green('Beginning update...'));
- await logExecution<void>({
- startMessage: 'Clearing existing Solr information...',
- endMessage: 'Solr information successfully cleared',
- action: Search.clear,
- color: cyan,
- });
- const cursor = await logExecution({
- startMessage: 'Connecting to and querying for all documents from database...',
- endMessage: ({ result, error }) => {
- const success = error === null && result !== undefined;
- if (!success) {
- console.log(red('Unable to connect to the database.'));
- process.exit(0);
- }
- return 'Connection successful and query complete';
- },
- action: () => Database.Instance.query({}),
- color: yellow,
- });
- const updates: any[] = [];
- let numDocs = 0;
- function updateDoc(doc: any) {
- numDocs++;
- if (numDocs % 50 === 0) {
- console.log(`Batch of 50 complete, total of ${numDocs}`);
- }
- if (doc.__type !== 'Doc') {
- return;
- }
- const { fields } = doc;
- if (!fields) {
- return;
- }
- const update2: any = { id: doc._id };
- let dynfield = false;
- fields.forEach((key: any) => {
- const value = fields[key];
- const term = ToSearchTerm(value);
- if (term !== undefined) {
- const { suffix, value: tvalue } = term;
- if (key.endsWith('modificationDate')) {
- update2['modificationDate' + suffix] = tvalue;
- }
- update2[key + suffix] = value;
- dynfield = true;
- }
- });
- if (dynfield) {
- updates.push(update2);
- }
- }
- await cursor?.forEach(updateDoc);
- const result = await logExecution({
- startMessage: `Dispatching updates for ${updates.length} documents`,
- endMessage: 'Dispatched updates complete',
- action: () => Search.updateDocuments(updates),
- color: cyan,
- });
- try {
- if (result) {
- const { status } = JSON.parse(result).responseHeader;
- console.log(status ? red(`Failed with status code (${status})`) : green('Success!'));
- } else {
- console.log(red('Solr is likely not running!'));
- }
- } catch (e) {
- console.log(red('Error:'));
- console.log(e);
- console.log('\n');
- }
- await cursor?.close();
- }
-
- const suffixMap: { [type: string]: string | [string, string | ((json: any) => any)] } = {
- number: '_n',
- string: '_t',
- boolean: '_b',
- image: ['_t', 'url'],
- video: ['_t', 'url'],
- pdf: ['_t', 'url'],
- audio: ['_t', 'url'],
- web: ['_t', 'url'],
- map: ['_t', 'url'],
- date: ['_d', value => new Date(value.date).toISOString()],
- proxy: ['_i', 'fieldId'],
- prefetch_proxy: ['_i', 'fieldId'],
- list: [
- '_l',
- list => {
- const results = [];
- // eslint-disable-next-line no-restricted-syntax
- for (const value of list.fields) {
- const term = ToSearchTerm(value);
- if (term) {
- results.push(term.value);
- }
- }
- return results.length ? results : null;
- },
- ],
- };
-
- function ToSearchTerm(valIn: any): { suffix: string; value: any } | undefined {
- let val = valIn;
- if (val === null || val === undefined) {
- return undefined;
- }
- const type = val.__type || typeof val;
- let suffix = suffixMap[type];
- if (!suffix) {
- return undefined;
- }
-
- if (Array.isArray(suffix)) {
- const accessor = suffix[1];
- if (typeof accessor === 'function') {
- val = accessor(val);
- } else {
- val = val[accessor];
- }
- // eslint-disable-next-line prefer-destructuring
- suffix = suffix[0];
- }
-
- return { suffix, value: val };
- }
-}
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index b2624f654..868373474 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -1,20 +1,18 @@
import * as AdmZip from 'adm-zip';
import * as formidable from 'formidable';
import * as fs from 'fs';
-import { createReadStream, createWriteStream, unlink } from 'fs';
+import { unlink } from 'fs';
import * as imageDataUri from 'image-data-uri';
-import Jimp from 'jimp';
import * as path from 'path';
import * as uuid from 'uuid';
import { retrocycle } from '../../decycler/decycler';
import { DashVersion } from '../../fields/DocSymbols';
-import { DashUploadUtils, InjectSize, SizeSuffix } from '../DashUploadUtils';
+import { DashUploadUtils, InjectSize, SizeSuffix, workerResample } from '../DashUploadUtils';
import { Method, _success } from '../RouteManager';
import { AcceptableMedia, Upload } from '../SharedMediaTypes';
-import { clientPathToFile, Directory, pathToDirectory, publicDirectory, serverPathToFile } from '../SocketData';
+import { Directory, clientPathToFile, pathToDirectory, publicDirectory, serverPathToFile } from '../SocketData';
import { Database } from '../database';
import ApiManager, { Registration } from './ApiManager';
-import { SolrManager } from './SearchManager';
export default class UploadManager extends ApiManager {
protected initialize(register: Registration): void {
@@ -185,7 +183,7 @@ export default class UploadManager extends ApiManager {
let linkids: string[] = [];
try {
// eslint-disable-next-line no-restricted-syntax
- for (const name in Object.keys(files)) {
+ for (const name in files) {
if (Object.prototype.hasOwnProperty.call(files, name)) {
const f = files[name];
// eslint-disable-next-line no-continue
@@ -194,26 +192,17 @@ export default class UploadManager extends ApiManager {
const zip = new AdmZip(path2.filepath);
zip.getEntries().forEach(entry => {
const entryName = entry.entryName.replace(/%%%/g, '/');
- if (!entryName.startsWith('files/')) {
- return;
- }
- const extension = path.extname(entryName);
- const pathname = publicDirectory + '/' + entry.entryName;
- const targetname = publicDirectory + '/' + entryName;
- try {
- zip.extractEntryTo(entry.entryName, publicDirectory, true, false);
- createReadStream(pathname).pipe(createWriteStream(targetname));
- Jimp.read(pathname).then(imgIn => {
- let img = imgIn;
- DashUploadUtils.imageResampleSizes(extension).forEach(({ width, suffix }) => {
- const outputPath = InjectSize(targetname, suffix);
- if (!width) createReadStream(pathname).pipe(createWriteStream(outputPath));
- else img = img.resize(width, Jimp.AUTO).write(outputPath);
- });
- unlink(pathname, () => {});
- });
- } catch (e) {
- console.log(e);
+ if (entryName.startsWith('files/')) {
+ const pathname = publicDirectory + '/' + entry.entryName;
+ const targetname = publicDirectory + '/' + entryName;
+ try {
+ zip.extractEntryTo(entry.entryName, publicDirectory, true, false);
+ const extension = path.extname(targetname).toLowerCase();
+ const basefilename = targetname.substring(0, targetname.length - extension.length);
+ workerResample(pathname, basefilename.replace(/_o$/, '') + extension, SizeSuffix.Original, true);
+ } catch (e) {
+ console.log(e);
+ }
}
});
const json = zip.getEntry('docs.json');
@@ -244,7 +233,6 @@ export default class UploadManager extends ApiManager {
unlink(path2.filepath, () => {});
}
}
- SolrManager.update();
res.send(JSON.stringify({ id, docids, linkids }) || 'error');
} catch (e) {
console.log(e);
@@ -287,16 +275,9 @@ export default class UploadManager extends ApiManager {
}
imageDataUri.outputFile(uri, serverPathToFile(Directory.images, InjectSize(filename, origSuffix))).then((savedName: string) => {
const ext = path.extname(savedName).toLowerCase();
+ const outputPath = serverPathToFile(Directory.images, filename + ext);
if (AcceptableMedia.imageFormats.includes(ext)) {
- Jimp.read(savedName).then(imgIn => {
- let img = imgIn;
- (!origSuffix ? [{ width: 400, suffix: SizeSuffix.Medium }] : Object.values(DashUploadUtils.Sizes)) //
- .forEach(({ width, suffix }) => {
- const outputPath = serverPathToFile(Directory.images, InjectSize(filename, suffix) + ext);
- if (!width) createReadStream(savedName).pipe(createWriteStream(outputPath));
- else img = img.resize(width, Jimp.AUTO).write(outputPath);
- });
- });
+ workerResample(savedName, outputPath, origSuffix, false);
}
res.send(clientPathToFile(Directory.images, filename + ext));
});
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index 8f012f783..1e55a885a 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -1,5 +1,5 @@
import axios from 'axios';
-import { spawn, exec } from 'child_process';
+import { exec, spawn } from 'child_process';
import { green, red } from 'colors';
import { ExifData, ExifImage } from 'exif';
import * as exifr from 'exifr';
@@ -8,8 +8,7 @@ import * as formidable from 'formidable';
import { File } from 'formidable';
import * as fs from 'fs';
import { createReadStream, createWriteStream, existsSync, readFileSync, rename, unlinkSync, writeFile } from 'fs';
-import Jimp from 'jimp';
-import * as autorotate from 'jpeg-autorotate';
+import { Jimp } from 'jimp';
import * as md5File from 'md5-file';
import * as path from 'path';
import { basename } from 'path';
@@ -23,6 +22,44 @@ import { AcceptableMedia, Upload } from './SharedMediaTypes';
import { Directory, clientPathToFile, filesDirectory, pathToDirectory, publicDirectory, serverPathToFile } from './SocketData';
import { resolvedServerUrl } from './server_Initialization';
+import { Worker, isMainThread, parentPort } from 'worker_threads';
+
+// Create an array to store worker threads
+enum workertasks {
+ JIMP = 'jimp',
+}
+const JimpWorker: Worker | undefined = isMainThread ? new Worker(__filename) : undefined;
+export const workerResample = (imgSourcePath: string, outputPath: string, origSuffix: SizeSuffix, unlinkSource: boolean) => {
+ JimpWorker?.postMessage({ task: workertasks.JIMP, imgSourcePath, outputPath, origSuffix, unlinkSource });
+};
+
+if (isMainThread) {
+ // main thread code if needed ...
+} else {
+ // Worker thread code - Listens for messages from the main thread
+ parentPort?.on('message', message => {
+ switch (message.task) {
+ case workertasks.JIMP:
+ return workerResampleImage(message);
+ default:
+ }
+ });
+
+ async function workerResampleImage(message: { imgSourcePath: string; outputPath: string; origSuffix: string; unlinkSource: boolean }) {
+ const { imgSourcePath, outputPath, origSuffix, unlinkSource } = message;
+ const sizes = !origSuffix ? [{ width: 400, suffix: SizeSuffix.Medium }] : DashUploadUtils.imageResampleSizes(path.extname(imgSourcePath));
+ // prettier-ignore
+ Jimp.read(imgSourcePath)
+ .then(img =>
+ sizes.forEach(({ width, suffix }) =>
+ img.resize({ w: width || img.bitmap.width })
+ .write(InjectSize(outputPath, suffix) as `${string}.${string}`)
+ ))
+ .catch(e => console.log('Error Jimp:', e))
+ .finally(() => unlinkSource && unlinkSync(imgSourcePath));
+ }
+}
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
const requestImageSize = require('../client/util/request-image-size');
@@ -277,15 +314,6 @@ export namespace DashUploadUtils {
}
};
- async function correctRotation(imgSourcePath: string) {
- const buffer = fs.readFileSync(imgSourcePath);
- try {
- return (await autorotate.rotate(buffer, { quality: 30 })).buffer;
- } catch (e) {
- return buffer;
- }
- }
-
/**
* define the resizers to use
* @param ext the extension
@@ -310,38 +338,23 @@ export namespace DashUploadUtils {
* @param outputDirectory the directory to output to, usually Directory.Images
* @returns a map with suffixes as keys and resized filenames as values.
*/
- export async function outputResizedImages(imgSourcePath: string, outputFileName: string, outputDirectory: string) {
+ export async function outputResizedImages(imgSourcePath: string, outputFileName: string, unlinkSource: boolean) {
const writtenFiles: { [suffix: string]: string } = {};
+ const outputPath = path.resolve(pathToDirectory(Directory.images), outputFileName);
const sizes = imageResampleSizes(path.extname(outputFileName));
- const imgBuffer = await correctRotation(imgSourcePath);
const imgReadStream = new Duplex();
- imgReadStream.push(imgBuffer);
+ imgReadStream.push(fs.readFileSync(imgSourcePath));
imgReadStream.push(null);
- const outputPath = (suffix: SizeSuffix) => {
- writtenFiles[suffix] = InjectSize(outputFileName, suffix);
- return path.resolve(outputDirectory, writtenFiles[suffix]);
- };
await Promise.all(
- sizes.filter(({ width }) => !width).map(({ suffix }) =>
- new Promise<void>(res => {
- imgReadStream.pipe(createWriteStream(outputPath(suffix))).on('close', res);
- })
+ sizes.map(({ suffix }) =>
+ new Promise<unknown>(res =>
+ imgReadStream.pipe(createWriteStream(writtenFiles[suffix] = InjectSize(outputPath, suffix))).on('close', res)
+ )
)); // prettier-ignore
- return Jimp.read(imgBuffer)
- .then(async imgIn => {
- let img = imgIn;
- await Promise.all( sizes.filter(({ width }) => width).map(({ width, suffix }) => {
- img = img.resize(width, Jimp.AUTO).write(outputPath(suffix));
- return img;
- } )); // prettier-ignore
- return writtenFiles;
- })
- .catch(e => {
- console.log('ERROR' + e);
- return writtenFiles;
- });
+ workerResample(imgSourcePath, outputPath, SizeSuffix.Original, unlinkSource);
+ return writtenFiles;
}
/**
@@ -387,8 +400,9 @@ export namespace DashUploadUtils {
writtenFiles = {};
}
} else {
+ const unlinkSrcWhenFinished = isLocal().test(source) && cleanUp;
try {
- writtenFiles = await outputResizedImages(metadata.source, resolved, pathToDirectory(Directory.images));
+ writtenFiles = await outputResizedImages(metadata.source, resolved, unlinkSrcWhenFinished);
} catch (e) {
// input is a blob or other, try reading it to create a metadata source file.
const reqSource = request(metadata.source);
@@ -400,16 +414,14 @@ export namespace DashUploadUtils {
.on('close', () => res())
.on('error', () => rej());
});
- writtenFiles = await outputResizedImages(readSource, resolved, pathToDirectory(Directory.images));
+ writtenFiles = await outputResizedImages(readSource, resolved, unlinkSrcWhenFinished);
fs.unlink(readSource, err => console.log("Couldn't unlink temporary image file:" + readSource, err));
}
}
Array.from(Object.keys(writtenFiles)).forEach(suffix => {
information.accessPaths[suffix] = getAccessPaths(images, writtenFiles[suffix]);
});
- if (isLocal().test(source) && cleanUp) {
- unlinkSync(source);
- }
+
return information;
};
diff --git a/src/server/index.ts b/src/server/index.ts
index 3e0d86814..88dbd232d 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -8,7 +8,6 @@ import DataVizManager from './ApiManagers/DataVizManager';
import DeleteManager from './ApiManagers/DeleteManager';
import DownloadManager from './ApiManagers/DownloadManager';
import GeneralGoogleManager from './ApiManagers/GeneralGoogleManager';
-import { SearchManager } from './ApiManagers/SearchManager';
import SessionManager from './ApiManagers/SessionManager';
import UploadManager from './ApiManagers/UploadManager';
import UserManager from './ApiManagers/UserManager';
@@ -67,7 +66,6 @@ function routeSetter({ addSupervisedRoute, logRegistrationOutcome }: RouteManage
new UserManager(),
new UploadManager(),
new DownloadManager(),
- new SearchManager(),
new DeleteManager(),
new UtilManager(),
new GeneralGoogleManager(),