aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--package-lock.json500
-rw-r--r--package.json4
-rw-r--r--src/ClientUtils.ts18
-rw-r--r--src/client/documents/DocumentTypes.ts1
-rw-r--r--src/client/documents/Documents.ts15
-rw-r--r--src/client/util/CurrentUserUtils.ts2
-rw-r--r--src/client/util/DocumentManager.ts4
-rw-r--r--src/client/util/node_modules/type_decls.d (renamed from src/typings/type_decls.d)0
-rw-r--r--src/client/views/DashboardView.tsx2
-rw-r--r--src/client/views/DocumentButtonBar.tsx18
-rw-r--r--src/client/views/FilterPanel.tsx26
-rw-r--r--src/client/views/TagsView.tsx25
-rw-r--r--src/client/views/collections/CollectionCalendarView.tsx4
-rw-r--r--src/client/views/collections/CollectionCardDeckView.scss18
-rw-r--r--src/client/views/collections/CollectionView.tsx4
-rw-r--r--src/client/views/nodes/FontIconBox/FontIconBox.tsx2
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx2
-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.tsx3
21 files changed, 533 insertions, 400 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/package-lock.json b/package-lock.json
index ebfda2072..16206807c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,9 +22,10 @@
"@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": "^6.0.1",
"@mui/material": "^6.0.1",
@@ -114,6 +115,7 @@
"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",
@@ -2916,6 +2918,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",
@@ -2927,6 +2945,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",
@@ -3161,13 +3190,13 @@
}
},
"node_modules/@jimp/core": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/core/-/core-1.2.0.tgz",
- "integrity": "sha512-omuAP/bmi45UUs76KE9hCfLOHT7+abvkcbOEUG267/sCVA19d1W2Ta78p3KNry23LSfFlvokGYFlO9tuvVdYiA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/core/-/core-1.3.0.tgz",
+ "integrity": "sha512-3+ndSrQYQxyyKyUSdXyk29vHt9vc3zg+3aFrVX2RHzAMeLdjkQHqzQc/7v6VxRk6BtOh1v/VPtmsXHXVg1vVhA==",
"dependencies": {
- "@jimp/file-ops": "1.2.0",
- "@jimp/types": "1.2.0",
- "@jimp/utils": "1.2.0",
+ "@jimp/file-ops": "1.3.0",
+ "@jimp/types": "1.3.0",
+ "@jimp/utils": "1.3.0",
"await-to-js": "^3.0.0",
"exif-parser": "^0.1.12",
"file-type": "^16.0.0",
@@ -3178,13 +3207,13 @@
}
},
"node_modules/@jimp/diff": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/diff/-/diff-1.2.0.tgz",
- "integrity": "sha512-Ln7smOEt/v68X+kduzGfIw+9D4tzXtMeWVP+y6unVma9TConssvuUDKknV/lPw7tsktPoMLtL3zJA+TRJ7+JHQ==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/diff/-/diff-1.3.0.tgz",
+ "integrity": "sha512-eGFfZi8UjSZ6gGu9kpQmGPRRDt5fMV3V1qKRn0cTqtBsECAnKPG5PPT1dvnjDDBbtAOH81jhIr//ko8H5WV8jg==",
"dependencies": {
- "@jimp/plugin-resize": "1.2.0",
- "@jimp/types": "1.2.0",
- "@jimp/utils": "1.2.0",
+ "@jimp/plugin-resize": "1.3.0",
+ "@jimp/types": "1.3.0",
+ "@jimp/utils": "1.3.0",
"pixelmatch": "^5.3.0"
},
"engines": {
@@ -3192,21 +3221,21 @@
}
},
"node_modules/@jimp/file-ops": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/file-ops/-/file-ops-1.2.0.tgz",
- "integrity": "sha512-LUipYM3d9OiccVfBGQ7TGzb/X++1ME2Rgbt/UhGPK32/iA1w+sW/edczXGJAG4Q+3PzTMXKir5znPNXL+dlOpw==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/file-ops/-/file-ops-1.3.0.tgz",
+ "integrity": "sha512-DzbSLgUdOGT9T9qf+Ik/hBA8e4zA9tWyHnJJA/N9sJHwHNDCMtoaX3KY5ssHuRGmcngGKLwbeGjddnZXF4oIVA==",
"engines": {
"node": ">=18"
}
},
"node_modules/@jimp/js-bmp": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/js-bmp/-/js-bmp-1.2.0.tgz",
- "integrity": "sha512-3JF++37nVK+V4mf7MMT5dUOf88GrcEoMt9/0fN1+gEF6EkjS7tAcx3cSInMa8geurZipsfY71XL7WTi/y8hziA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/js-bmp/-/js-bmp-1.3.0.tgz",
+ "integrity": "sha512-sc3jvJJOMHoUtP9mlnuBCkwhHy9T2KiSfdV3XKg81v+bg9O0LudB33v3Y0dtGxSo/WOL2V6PVNIWTRf7gu+hJw==",
"dependencies": {
- "@jimp/core": "1.2.0",
- "@jimp/types": "1.2.0",
- "@jimp/utils": "1.2.0",
+ "@jimp/core": "1.3.0",
+ "@jimp/types": "1.3.0",
+ "@jimp/utils": "1.3.0",
"bmp-ts": "^1.0.9"
},
"engines": {
@@ -3214,12 +3243,12 @@
}
},
"node_modules/@jimp/js-gif": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/js-gif/-/js-gif-1.2.0.tgz",
- "integrity": "sha512-7OV8ph3rGzOJ6nSQv7+m8fyIeeshg5b1h6hlD18dCO7qamPnJdc2M5+of1Fte2D7qDL8Az2vT6vgKPP05O/HHg==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/js-gif/-/js-gif-1.3.0.tgz",
+ "integrity": "sha512-hhAd/TpZSp6AIuRjYKFGGEsu9HzQG16Q9lZHPcTZz1TlxtTUqW60AJvFrGvnUZbTecDj3JnI3TipX8aeqZpBDg==",
"dependencies": {
- "@jimp/core": "1.2.0",
- "@jimp/types": "1.2.0",
+ "@jimp/core": "1.3.0",
+ "@jimp/types": "1.3.0",
"gifwrap": "^0.10.1",
"omggif": "^1.0.10"
},
@@ -3228,12 +3257,12 @@
}
},
"node_modules/@jimp/js-jpeg": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/js-jpeg/-/js-jpeg-1.2.0.tgz",
- "integrity": "sha512-7YYl8jEHCTX2XVjUZJOHAROFDHmx8diM+fEMgGhM4teOAKNM5xVDXSnC16h/qyspHqgDDQgI16gszmo6MF3W4Q==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/js-jpeg/-/js-jpeg-1.3.0.tgz",
+ "integrity": "sha512-SrZL35FvKsgySS5kpqYWbVsi0rswcgxw3oRTVOy55q8F045fE4U0YqlnRdkg77dxdahUOIWVhvn5+0V+Re5F5A==",
"dependencies": {
- "@jimp/core": "1.2.0",
- "@jimp/types": "1.2.0",
+ "@jimp/core": "1.3.0",
+ "@jimp/types": "1.3.0",
"jpeg-js": "^0.4.4"
},
"engines": {
@@ -3241,12 +3270,12 @@
}
},
"node_modules/@jimp/js-png": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/js-png/-/js-png-1.2.0.tgz",
- "integrity": "sha512-toW5aqFH/alybkP2IZSLHa18O5lpwJpB5JqNQEYT1KU30V/czyUdpznlCV50PVXHZnQbb48MKJzfpLqj0O7KBA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/js-png/-/js-png-1.3.0.tgz",
+ "integrity": "sha512-9x8uFueVupNocQQ5WEFat61M31MdRDV7O3QBDR2iEsbVeQ1+LE9Tvvm9r1PG9W91KZYzG4IYPPsogQ0TFEixqA==",
"dependencies": {
- "@jimp/core": "1.2.0",
- "@jimp/types": "1.2.0",
+ "@jimp/core": "1.3.0",
+ "@jimp/types": "1.3.0",
"pngjs": "^7.0.0"
},
"engines": {
@@ -3254,12 +3283,12 @@
}
},
"node_modules/@jimp/js-tiff": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/js-tiff/-/js-tiff-1.2.0.tgz",
- "integrity": "sha512-RhXqdkB7lhpCW9uKVXmLhFI+Inpj7CcP8GNMMWpPcYaWw8aGUqZjgdy/81nudIdXmvk4eKI5NdtWptCVzRFvsQ==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/js-tiff/-/js-tiff-1.3.0.tgz",
+ "integrity": "sha512-uin5WkVm0M8ZgotIANXU0sfVkNApsKws1ZSqsc9NZf0MYJsZkz/w8D4ld6hXkFCEQcJ/TMu7aeMZSP+I8cbmOg==",
"dependencies": {
- "@jimp/core": "1.2.0",
- "@jimp/types": "1.2.0",
+ "@jimp/core": "1.3.0",
+ "@jimp/types": "1.3.0",
"utif2": "^4.1.0"
},
"engines": {
@@ -3267,12 +3296,12 @@
}
},
"node_modules/@jimp/plugin-blit": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-1.2.0.tgz",
- "integrity": "sha512-y18/qt/FdINIQefmYSI6ownb1VtOsR3Y43H8JwzcsuSmpZLpF+lJwXoZLFzgCSSCpiQyb+z924k6L11C4uKH3g==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-1.3.0.tgz",
+ "integrity": "sha512-5OjEUM0jtzQ6KJBTougs8ozbUAxYyJiKZqceFb8mqKVMjuiM94N9425mIDDgOl5MDFwAESeTMIchKCAPMOv2FQ==",
"dependencies": {
- "@jimp/types": "1.2.0",
- "@jimp/utils": "1.2.0",
+ "@jimp/types": "1.3.0",
+ "@jimp/utils": "1.3.0",
"zod": "^3.23.8"
},
"engines": {
@@ -3280,23 +3309,23 @@
}
},
"node_modules/@jimp/plugin-blur": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-1.2.0.tgz",
- "integrity": "sha512-h0/4W2zjkrDC9nZGl1r+pk5ftG6d1Zdvza/BE7xie++P2ihGp4ikgK26Hn/xlnAH691yh/uCjP0eeJw+Ggfy5Q==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-1.3.0.tgz",
+ "integrity": "sha512-108RHeCvHFJqpQvuaydhxwJLBwdjEWKLW6ZXWWCnCadrpKbH2yqu9P6oUhHS7atLjQ0ZBzXcM+Wj2VYR7XU8ng==",
"dependencies": {
- "@jimp/core": "1.2.0",
- "@jimp/utils": "1.2.0"
+ "@jimp/core": "1.3.0",
+ "@jimp/utils": "1.3.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@jimp/plugin-circle": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-1.2.0.tgz",
- "integrity": "sha512-rfPOsLAnQ+YpmGttJRbmTHP2V5Q1Ca99HcpaF8NqOVC9cotGu+Ux3xJIo9QKxyDTO/uwx15KTwzbQAbE43Mr0A==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-1.3.0.tgz",
+ "integrity": "sha512-Lkz1uwD2wgysuu4TDzAVQ26+urr+siYlO/qXnMYHui9k0P735S6B6EsWrzssLDGOtqevQyYcx5u6h0Kv4lzehg==",
"dependencies": {
- "@jimp/types": "1.2.0",
+ "@jimp/types": "1.3.0",
"zod": "^3.23.8"
},
"engines": {
@@ -3304,13 +3333,13 @@
}
},
"node_modules/@jimp/plugin-color": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-1.2.0.tgz",
- "integrity": "sha512-RdDj1ZyUN478hwCbR004xQK2qJ+FQvL0F+fGVUOozpw4pWs6G0PKtGWooKGB0522sEw3tvvb5mHDnz06WWIU0w==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-1.3.0.tgz",
+ "integrity": "sha512-HLFtZB86W2nVnfZT+LAsyooF9efapWPmxuOKECeevunb1zHieO1ni19QXJfcqtt+cVj8UxIBGC4v9IFDJ9PGYw==",
"dependencies": {
- "@jimp/core": "1.2.0",
- "@jimp/types": "1.2.0",
- "@jimp/utils": "1.2.0",
+ "@jimp/core": "1.3.0",
+ "@jimp/types": "1.3.0",
+ "@jimp/utils": "1.3.0",
"tinycolor2": "^1.6.0",
"zod": "^3.23.8"
},
@@ -3319,15 +3348,15 @@
}
},
"node_modules/@jimp/plugin-contain": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-1.2.0.tgz",
- "integrity": "sha512-YZmQnP0eJbBUhDr4YuvfsQl04CFEwTy+EKgMX7fCc5Ne/l0Y4wiabUtB2Cr47tvIoQiOzmx8UV5jnoYJFO6CQw==",
- "dependencies": {
- "@jimp/core": "1.2.0",
- "@jimp/plugin-blit": "1.2.0",
- "@jimp/plugin-resize": "1.2.0",
- "@jimp/types": "1.2.0",
- "@jimp/utils": "1.2.0",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-1.3.0.tgz",
+ "integrity": "sha512-1xPJ/CC4hh8IDrZFCtwQezw0RFzdrFvatzXkmfZD0cRyUXtYQ8VzExeK9MXLWi2+/nfufh+2SIhThTQ8xIzLBw==",
+ "dependencies": {
+ "@jimp/core": "1.3.0",
+ "@jimp/plugin-blit": "1.3.0",
+ "@jimp/plugin-resize": "1.3.0",
+ "@jimp/types": "1.3.0",
+ "@jimp/utils": "1.3.0",
"zod": "^3.23.8"
},
"engines": {
@@ -3335,14 +3364,14 @@
}
},
"node_modules/@jimp/plugin-cover": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-1.2.0.tgz",
- "integrity": "sha512-EnCibB1mMSFRoIW8h53lvEAWXFb+H6iIjCoKAVuMIkPq6nhc7WCDuvvgn+oLnYaNPSsD5+ge+pafdIaAlw+jpA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-1.3.0.tgz",
+ "integrity": "sha512-Q8vlXepruKU+A55PS2A+d7TPwIoYthnX61ae+TQa+/4DjYk6XZA2YlmUFhq7P3RH5p288N/84ILNSIwH5YCqAw==",
"dependencies": {
- "@jimp/core": "1.2.0",
- "@jimp/plugin-crop": "1.2.0",
- "@jimp/plugin-resize": "1.2.0",
- "@jimp/types": "1.2.0",
+ "@jimp/core": "1.3.0",
+ "@jimp/plugin-crop": "1.3.0",
+ "@jimp/plugin-resize": "1.3.0",
+ "@jimp/types": "1.3.0",
"zod": "^3.23.8"
},
"engines": {
@@ -3350,13 +3379,13 @@
}
},
"node_modules/@jimp/plugin-crop": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-1.2.0.tgz",
- "integrity": "sha512-jVq3zlrcYwnVKIS8NTCeOoJ8sWrn9Th4qDQWu7hbo6tgEAYXZCEBPC3zQzeu7RY9oETorJ3Q7zKzyKO8xzBedw==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-1.3.0.tgz",
+ "integrity": "sha512-AoCTYFgcDEH+sqc2IQ5CI0CgYrQZSFfZ6q4zSXkWA+irs1nDbjJeA+0vClkYxJNSkk2wqB0fys69OBoqfDabrw==",
"dependencies": {
- "@jimp/core": "1.2.0",
- "@jimp/types": "1.2.0",
- "@jimp/utils": "1.2.0",
+ "@jimp/core": "1.3.0",
+ "@jimp/types": "1.3.0",
+ "@jimp/utils": "1.3.0",
"zod": "^3.23.8"
},
"engines": {
@@ -3364,12 +3393,12 @@
}
},
"node_modules/@jimp/plugin-displace": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-1.2.0.tgz",
- "integrity": "sha512-XAm+y2xX95cioc4Ya9RlxiDRbfQ6+DF6B6nHRkzwUYN3TaB698PS8fBkBZ4VlMQ8IqD+Y+OKcEDhpWz28GqUVg==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-1.3.0.tgz",
+ "integrity": "sha512-8t/R0SjE7YWujeMLbUT2js9WIeyFbeQXxAiCPt4AJy1BUD56sbcWIx1zJzrL52eF+bG4AS8oLOp5arL+P7ocmQ==",
"dependencies": {
- "@jimp/types": "1.2.0",
- "@jimp/utils": "1.2.0",
+ "@jimp/types": "1.3.0",
+ "@jimp/utils": "1.3.0",
"zod": "^3.23.8"
},
"engines": {
@@ -3377,23 +3406,23 @@
}
},
"node_modules/@jimp/plugin-dither": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-1.2.0.tgz",
- "integrity": "sha512-NoOeeOhqFoIBqHnJtXkkknWCykOQzH/duYTb4JTxRaHKAIelQAvDbxanLu+S7wp3brIvurJM9RDxYK0Gqd7k5A==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-1.3.0.tgz",
+ "integrity": "sha512-oE6kHne88OOcJBu+fk9KvMMB71UZUO4B2YYoaHVjGbtciPG9FbBBGqgD9oULVWhHuICZdDnfgFF0hhemQuQloQ==",
"dependencies": {
- "@jimp/types": "1.2.0"
+ "@jimp/types": "1.3.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@jimp/plugin-fisheye": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-1.2.0.tgz",
- "integrity": "sha512-N5UG6vbpQkYbhYAWJcreR2vC0fWWxf9VUupDaIOM1Yp9h5Lel/8Q0o2ie5yUxsHt2wa0HOm0O9KorfHzlV6s5A==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-1.3.0.tgz",
+ "integrity": "sha512-VLaqY/IxrqHyjKeWpUwJZpAqug4DE26hM/8ejfPm5FmofAS1dI0deecDfbthRbw17hnPVcAiTkZ6QTiQL71Z4w==",
"dependencies": {
- "@jimp/types": "1.2.0",
- "@jimp/utils": "1.2.0",
+ "@jimp/types": "1.3.0",
+ "@jimp/utils": "1.3.0",
"zod": "^3.23.8"
},
"engines": {
@@ -3401,11 +3430,11 @@
}
},
"node_modules/@jimp/plugin-flip": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-1.2.0.tgz",
- "integrity": "sha512-zI5/6dkoUdslf7BMccXURIQzXKKXu/ocTTnzf3C6VHV4M6U/QIg1BLi8A5+KkgHnvpuSM/IW3T0PDWKLpmK/CA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-1.3.0.tgz",
+ "integrity": "sha512-cHeefBsjBYLbjqq8TFJHQD/6sgJLvb6XPdB8wVvKe682Y8jIilxlEhZJeUFXwsMrKKhbXNZxmtSc/pEIYCo6cA==",
"dependencies": {
- "@jimp/types": "1.2.0",
+ "@jimp/types": "1.3.0",
"zod": "^3.23.8"
},
"engines": {
@@ -3413,19 +3442,19 @@
}
},
"node_modules/@jimp/plugin-hash": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-hash/-/plugin-hash-1.2.0.tgz",
- "integrity": "sha512-opj35tK+Ku+17mq9Ip7GEwDpNr+Mk/xQcOGLBispbKLWqAG1IDyHTLSsAmDcM8pL4AXXv/96xPUWWxu4mZLwTw==",
- "dependencies": {
- "@jimp/core": "1.2.0",
- "@jimp/js-bmp": "1.2.0",
- "@jimp/js-jpeg": "1.2.0",
- "@jimp/js-png": "1.2.0",
- "@jimp/js-tiff": "1.2.0",
- "@jimp/plugin-color": "1.2.0",
- "@jimp/plugin-resize": "1.2.0",
- "@jimp/types": "1.2.0",
- "@jimp/utils": "1.2.0",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-hash/-/plugin-hash-1.3.0.tgz",
+ "integrity": "sha512-LAUi9FFT3Kp2bI2hWXQ75t1pl6q6ZyKH/jJQZg8DPL+fFK0//TIsw/g0VxW5lZoV3mHUUorQlsZzWtNi/DGtWA==",
+ "dependencies": {
+ "@jimp/core": "1.3.0",
+ "@jimp/js-bmp": "1.3.0",
+ "@jimp/js-jpeg": "1.3.0",
+ "@jimp/js-png": "1.3.0",
+ "@jimp/js-tiff": "1.3.0",
+ "@jimp/plugin-color": "1.3.0",
+ "@jimp/plugin-resize": "1.3.0",
+ "@jimp/types": "1.3.0",
+ "@jimp/utils": "1.3.0",
"any-base": "^1.1.0"
},
"engines": {
@@ -3433,11 +3462,11 @@
}
},
"node_modules/@jimp/plugin-mask": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-1.2.0.tgz",
- "integrity": "sha512-VLGifoXRyddUDbUj0LIG3HrEeCZOHSzfOcv/bXyQq7/KHmR+HnhaAuDOlkDLBa4buZMbh4Ub+nhmDhU3kwf8yA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-1.3.0.tgz",
+ "integrity": "sha512-fpU6rZ75c1gD6/8zsiPQW57+doX3KfexZ3lVYToyd720HPO/qfG9lzwfY30tJVXArI4DMbG8qN7lXKgGeWwGqw==",
"dependencies": {
- "@jimp/types": "1.2.0",
+ "@jimp/types": "1.3.0",
"zod": "^3.23.8"
},
"engines": {
@@ -3445,15 +3474,15 @@
}
},
"node_modules/@jimp/plugin-print": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-1.2.0.tgz",
- "integrity": "sha512-TLfne5npxCkf8CY/UuCT589GpKQsjQrcj6SjdVpcddGdm25t3jEt4+WE6wPFsOuocWZO6YSaJNOQJKma/BRQ3w==",
- "dependencies": {
- "@jimp/core": "1.2.0",
- "@jimp/js-jpeg": "1.2.0",
- "@jimp/js-png": "1.2.0",
- "@jimp/plugin-blit": "1.2.0",
- "@jimp/types": "1.2.0",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-1.3.0.tgz",
+ "integrity": "sha512-WeN35Fo9Bushm6VGUdQXqXrVIFDYECeKLKN+LlAqQ/YnIlUiTirPlcyGHzEBKD8uXDCmjBYqxwadcPvRDVwFEw==",
+ "dependencies": {
+ "@jimp/core": "1.3.0",
+ "@jimp/js-jpeg": "1.3.0",
+ "@jimp/js-png": "1.3.0",
+ "@jimp/plugin-blit": "1.3.0",
+ "@jimp/types": "1.3.0",
"parse-bmfont-ascii": "^1.0.6",
"parse-bmfont-binary": "^1.0.6",
"parse-bmfont-xml": "^1.1.6",
@@ -3465,9 +3494,9 @@
}
},
"node_modules/@jimp/plugin-quantize": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-quantize/-/plugin-quantize-1.2.0.tgz",
- "integrity": "sha512-0sYazEK2sT1NXFInwcef0ag0X3qicqI07vUFnv4bKtxILU00tWhUyig3h6kLzZhFdiTGXt2MP3OGCu4mWQ8OfQ==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-quantize/-/plugin-quantize-1.3.0.tgz",
+ "integrity": "sha512-4Hgp5UNN8DGeX1ULNANPwlHCyuaZYZPJ/mpe/lnCN4jLI/SeBzR4g8tU+srNF6arPwRXrLNQV6T/ehAa7zhbkg==",
"dependencies": {
"image-q": "^4.0.0",
"zod": "^3.23.8"
@@ -3477,12 +3506,12 @@
}
},
"node_modules/@jimp/plugin-resize": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-1.2.0.tgz",
- "integrity": "sha512-QZd72r988QdAYQs9jggHsCdatbybkU3WmVxqE0l3YbpltW13tdiMktsNTSyQT1nci7l3LvrBRuNl6pOQx7Ug5w==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-1.3.0.tgz",
+ "integrity": "sha512-9fMw6ff/3kzDwQ2rGNYCJ2jc9IHsxQh9eaoPb4SkVHxzq+O3yka3M2Vjf41gaYhQ5Pt5QLgQ9uYUA+2kp1RF1g==",
"dependencies": {
- "@jimp/core": "1.2.0",
- "@jimp/types": "1.2.0",
+ "@jimp/core": "1.3.0",
+ "@jimp/types": "1.3.0",
"zod": "^3.23.8"
},
"engines": {
@@ -3490,15 +3519,15 @@
}
},
"node_modules/@jimp/plugin-rotate": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-1.2.0.tgz",
- "integrity": "sha512-P0dvX6XlerHK6Om1rUs9kAxqbmk94VCPxuzJk5asUliOtq+wklLTfRbcmn3fQkn9xH3EtQojdE0RAVCExMkOdg==",
- "dependencies": {
- "@jimp/core": "1.2.0",
- "@jimp/plugin-crop": "1.2.0",
- "@jimp/plugin-resize": "1.2.0",
- "@jimp/types": "1.2.0",
- "@jimp/utils": "1.2.0",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-1.3.0.tgz",
+ "integrity": "sha512-lpzk37tzk7b5RG5U6P/E3vk+bwU86TnNZOc1LHQeTOEpfFAPMTJl6w+OlLLxVNJ7HUQege/8P47N2onQX00wXw==",
+ "dependencies": {
+ "@jimp/core": "1.3.0",
+ "@jimp/plugin-crop": "1.3.0",
+ "@jimp/plugin-resize": "1.3.0",
+ "@jimp/types": "1.3.0",
+ "@jimp/utils": "1.3.0",
"zod": "^3.23.8"
},
"engines": {
@@ -3506,15 +3535,15 @@
}
},
"node_modules/@jimp/plugin-threshold": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-1.2.0.tgz",
- "integrity": "sha512-yMibcCFQ1NLx94DFdGqPG0z3EiOohgbYhDYpqMmadBu1IUOcHl8EnCJjD673RZxQh/4s6MR6vpcT5epjtFVnGg==",
- "dependencies": {
- "@jimp/core": "1.2.0",
- "@jimp/plugin-color": "1.2.0",
- "@jimp/plugin-hash": "1.2.0",
- "@jimp/types": "1.2.0",
- "@jimp/utils": "1.2.0",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-1.3.0.tgz",
+ "integrity": "sha512-lKBzZEgjI/zM51/muGyL2juGEkK361/yFpRcmjafIijq0sHNww1rhqSa0AhO80iCmN77A4Ym/oelY0qh4mtlLQ==",
+ "dependencies": {
+ "@jimp/core": "1.3.0",
+ "@jimp/plugin-color": "1.3.0",
+ "@jimp/plugin-hash": "1.3.0",
+ "@jimp/types": "1.3.0",
+ "@jimp/utils": "1.3.0",
"zod": "^3.23.8"
},
"engines": {
@@ -3522,9 +3551,9 @@
}
},
"node_modules/@jimp/types": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/types/-/types-1.2.0.tgz",
- "integrity": "sha512-Zjt+cV0f9Txnx9xdT+SJeNVgbgsQdtMTNWF8W6OAs3pLI9KaAelsXLi9F9jWikoctAI58GU/LOG52LLQkE/5qQ==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/types/-/types-1.3.0.tgz",
+ "integrity": "sha512-K4RaTmDTqZqbjjwOtxzVH9QyCgQBukXjKOmdgNuCmu7ugrpeTeWV7SvrwZZPhTt31lmja8A3a3Dw1ScVZdtmyA==",
"dependencies": {
"zod": "^3.23.8"
},
@@ -3533,11 +3562,11 @@
}
},
"node_modules/@jimp/utils": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-1.2.0.tgz",
- "integrity": "sha512-7/CIawD7fKfzG1QWU66nS5JxLNbhCiYuv6ce2ytJUzzPPLrJ0X250cS0kb30FvPaNu42DfvJUMUjxbg+9Ia79g==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-1.3.0.tgz",
+ "integrity": "sha512-QIye6IWJaQ3Q9+6rxgQiFI1I7MwrQZYxlhYhPolJv+BfCXBT8XWJymV8J75vlnjvz3kN2AMXAEU7c7w0h2Tz3Q==",
"dependencies": {
- "@jimp/types": "1.2.0",
+ "@jimp/types": "1.3.0",
"tinycolor2": "^1.6.0"
},
"engines": {
@@ -9658,9 +9687,9 @@
"integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g=="
},
"node_modules/@types/node": {
- "version": "22.5.3",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.3.tgz",
- "integrity": "sha512-njripolh85IA9SQGTAqbmnNZTdxv7X/4OYGPz8tgy5JDr8MP+uDBa921GpYEoDDnwm0Hmn5ZPeJgiiSTPoOzkQ==",
+ "version": "22.5.4",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz",
+ "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==",
"dependencies": {
"undici-types": "~6.19.2"
}
@@ -10380,36 +10409,36 @@
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ=="
},
"node_modules/@vue/compiler-core": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.0.tgz",
- "integrity": "sha512-ja7cpqAOfw4tyFAxgBz70Z42miNDeaqTxExTsnXDLomRpqfyCgyvZvFp482fmsElpfvsoMJUsvzULhvxUTW6Iw==",
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.1.tgz",
+ "integrity": "sha512-WdjF+NSgFYdWttHevHw5uaJFtKPalhmxhlu2uREj8cLP0uyKKIR60/JvSZNTp0x+NSd63iTiORQTx3+tt55NWQ==",
"dependencies": {
"@babel/parser": "^7.25.3",
- "@vue/shared": "3.5.0",
+ "@vue/shared": "3.5.1",
"entities": "^4.5.0",
"estree-walker": "^2.0.2",
"source-map-js": "^1.2.0"
}
},
"node_modules/@vue/compiler-dom": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.0.tgz",
- "integrity": "sha512-xYjUybWZXl+1R/toDy815i4PbeehL2hThiSGkcpmIOCy2HoYyeeC/gAWK/Y/xsoK+GSw198/T5O31bYuQx5uvQ==",
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.1.tgz",
+ "integrity": "sha512-Ao23fB1lINo18HLCbJVApvzd9OQe8MgmQSgyY5+umbWj2w92w9KykVmJ4Iv2US5nak3ixc2B+7Km7JTNhQ8kSQ==",
"dependencies": {
- "@vue/compiler-core": "3.5.0",
- "@vue/shared": "3.5.0"
+ "@vue/compiler-core": "3.5.1",
+ "@vue/shared": "3.5.1"
}
},
"node_modules/@vue/compiler-sfc": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.0.tgz",
- "integrity": "sha512-B9DgLtrqok2GLuaFjLlSL15ZG3ZDBiitUH1ecex9guh/ZcA5MCdwuVE6nsfQxktuZY/QY0awJ35/ripIviCQTQ==",
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.1.tgz",
+ "integrity": "sha512-DFizMNH8eDglLhlfwJ0+ciBsztaYe3fY/zcZjrqL1ljXvUw/UpC84M1d7HpBTCW68SNqZyIxrs1XWmf+73Y65w==",
"dependencies": {
"@babel/parser": "^7.25.3",
- "@vue/compiler-core": "3.5.0",
- "@vue/compiler-dom": "3.5.0",
- "@vue/compiler-ssr": "3.5.0",
- "@vue/shared": "3.5.0",
+ "@vue/compiler-core": "3.5.1",
+ "@vue/compiler-dom": "3.5.1",
+ "@vue/compiler-ssr": "3.5.1",
+ "@vue/shared": "3.5.1",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.11",
"postcss": "^8.4.44",
@@ -10417,18 +10446,18 @@
}
},
"node_modules/@vue/compiler-ssr": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.0.tgz",
- "integrity": "sha512-E263QZmA1dqRd7c3u/sWTLRMpQOT0aZ8av/L9SoD/v/BVMZaWFHPUUBswS+bzrfvG2suJF8vSLKx6k6ba5SUdA==",
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.1.tgz",
+ "integrity": "sha512-C1hpSHQgRM8bg+5XWWD7CkFaVpSn9wZHCLRd10AmxqrH17d4EMP6+XcZpwBOM7H1jeStU5naEapZZWX0kso1tQ==",
"dependencies": {
- "@vue/compiler-dom": "3.5.0",
- "@vue/shared": "3.5.0"
+ "@vue/compiler-dom": "3.5.1",
+ "@vue/shared": "3.5.1"
}
},
"node_modules/@vue/shared": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.0.tgz",
- "integrity": "sha512-m9IgiteBpCkFaMNwCOBkFksA7z8QiKc30ooRuoXWUFRDu0mGyNPlFHmbncF0/Kra1RlX8QrmBbRaIxVvikaR0Q=="
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.1.tgz",
+ "integrity": "sha512-NdcTRoO4KuW2RSFgpE2c+E/R/ZHaRzWPxAGxhmxZaaqLh6nYCXx7lc9a88ioqOCxCaV2SFJmujkxbUScW7dNsQ=="
},
"node_modules/@webassemblyjs/ast": {
"version": "1.12.1",
@@ -19166,6 +19195,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",
@@ -21879,37 +21921,37 @@
}
},
"node_modules/jimp": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/jimp/-/jimp-1.2.0.tgz",
- "integrity": "sha512-oNqOurG39OYE50TqFoYoHhMbZ8eUiTOtQ2MFPzfdXLUzjNsB7qJUR1ZJRGep4JfFhjf2G0HJiYoqDR2XkXHR/A==",
- "dependencies": {
- "@jimp/core": "1.2.0",
- "@jimp/diff": "1.2.0",
- "@jimp/js-bmp": "1.2.0",
- "@jimp/js-gif": "1.2.0",
- "@jimp/js-jpeg": "1.2.0",
- "@jimp/js-png": "1.2.0",
- "@jimp/js-tiff": "1.2.0",
- "@jimp/plugin-blit": "1.2.0",
- "@jimp/plugin-blur": "1.2.0",
- "@jimp/plugin-circle": "1.2.0",
- "@jimp/plugin-color": "1.2.0",
- "@jimp/plugin-contain": "1.2.0",
- "@jimp/plugin-cover": "1.2.0",
- "@jimp/plugin-crop": "1.2.0",
- "@jimp/plugin-displace": "1.2.0",
- "@jimp/plugin-dither": "1.2.0",
- "@jimp/plugin-fisheye": "1.2.0",
- "@jimp/plugin-flip": "1.2.0",
- "@jimp/plugin-hash": "1.2.0",
- "@jimp/plugin-mask": "1.2.0",
- "@jimp/plugin-print": "1.2.0",
- "@jimp/plugin-quantize": "1.2.0",
- "@jimp/plugin-resize": "1.2.0",
- "@jimp/plugin-rotate": "1.2.0",
- "@jimp/plugin-threshold": "1.2.0",
- "@jimp/types": "1.2.0",
- "@jimp/utils": "1.2.0"
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/jimp/-/jimp-1.3.0.tgz",
+ "integrity": "sha512-eJnVMuqDQ545taNLp13gVZynnoOvE0xZ2Oti9alkld47dNhmFHBmFTBMTYaZr7zceGTf54RGdr7C4d2WUNwc0g==",
+ "dependencies": {
+ "@jimp/core": "1.3.0",
+ "@jimp/diff": "1.3.0",
+ "@jimp/js-bmp": "1.3.0",
+ "@jimp/js-gif": "1.3.0",
+ "@jimp/js-jpeg": "1.3.0",
+ "@jimp/js-png": "1.3.0",
+ "@jimp/js-tiff": "1.3.0",
+ "@jimp/plugin-blit": "1.3.0",
+ "@jimp/plugin-blur": "1.3.0",
+ "@jimp/plugin-circle": "1.3.0",
+ "@jimp/plugin-color": "1.3.0",
+ "@jimp/plugin-contain": "1.3.0",
+ "@jimp/plugin-cover": "1.3.0",
+ "@jimp/plugin-crop": "1.3.0",
+ "@jimp/plugin-displace": "1.3.0",
+ "@jimp/plugin-dither": "1.3.0",
+ "@jimp/plugin-fisheye": "1.3.0",
+ "@jimp/plugin-flip": "1.3.0",
+ "@jimp/plugin-hash": "1.3.0",
+ "@jimp/plugin-mask": "1.3.0",
+ "@jimp/plugin-print": "1.3.0",
+ "@jimp/plugin-quantize": "1.3.0",
+ "@jimp/plugin-resize": "1.3.0",
+ "@jimp/plugin-rotate": "1.3.0",
+ "@jimp/plugin-threshold": "1.3.0",
+ "@jimp/types": "1.3.0",
+ "@jimp/utils": "1.3.0"
},
"engines": {
"node": ">=18"
@@ -27318,13 +27360,13 @@
}
},
"node_modules/openai": {
- "version": "4.57.1",
- "resolved": "https://registry.npmjs.org/openai/-/openai-4.57.1.tgz",
- "integrity": "sha512-7q+4U9A/klaAT40bqL6sPFhIKb4jsUJ8udddCzaf8mdwICYeBG7grps/zDcrOUfkwCxCzR6fxfDDah3WqHoVUA==",
+ "version": "4.57.3",
+ "resolved": "https://registry.npmjs.org/openai/-/openai-4.57.3.tgz",
+ "integrity": "sha512-mTz5/SmulkkeSpqbSr6WNLRU6krkyhnbfRUC8XfaXbj1T6xUorKEELjZvbRSzI714JLOk1MeFkqYS9H4WHhqDQ==",
"dependencies": {
"@types/node": "^18.11.18",
"@types/node-fetch": "^2.6.4",
- "@types/qs": "^6.9.7",
+ "@types/qs": "^6.9.15",
"abort-controller": "^3.0.0",
"agentkeepalive": "^4.2.1",
"form-data-encoder": "1.7.2",
@@ -27345,9 +27387,9 @@
}
},
"node_modules/openai/node_modules/@types/node": {
- "version": "18.19.49",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.49.tgz",
- "integrity": "sha512-ALCeIR6n0nQ7j0FUF1ycOhrp6+XutJWqEu/vtdEqXFUQwkBfgUA5cEg3ZNmjWGF/ZYA/FcF9QMkL55Ar0O6UrA==",
+ "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"
}
@@ -29033,9 +29075,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"
diff --git a/package.json b/package.json
index 5c7e69ff5..e5c24f4dd 100644
--- a/package.json
+++ b/package.json
@@ -102,9 +102,10 @@
"@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": "^6.0.1",
"@mui/material": "^6.0.1",
@@ -194,6 +195,7 @@
"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",
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/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index b055546fc..56d505681 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -39,7 +39,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 af181b031..d5a7b0465 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -450,6 +450,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)');
@@ -912,7 +913,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,10 +978,6 @@ 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);
}
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 14fb65252..f042f33ce 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -787,7 +787,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_)'} },
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/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/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.tsx b/src/client/views/DocumentButtonBar.tsx
index 58b7f207c..437ef045f 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -264,23 +264,6 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (
}
@computed
- get calendarButton() {
- const targetDoc = this.view0?.Document;
- return !targetDoc ? null : (
- <Tooltip title={<div className="dash-calendar-button">Open calendar menu</div>}>
- <div
- className="documentButtonBar-icon"
- style={{ color: 'white' }}
- onClick={() => {
- CalendarManager.Instance.open(this.view0, targetDoc);
- }}>
- <FontAwesomeIcon className="documentdecorations-icon" icon={faCalendarDays as IconLookup} />
- </div>
- </Tooltip>
- );
- }
-
- @computed
get keywordButton() {
return !DocumentView.Selected().length ? null : (
<Tooltip title={<div className="dash-keyword-button">Open keyword menu</div>}>
@@ -460,7 +443,6 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (
{!DocumentView.Selected().some(v => v.allLinks.length) ? null : <div className="documentButtonBar-button">{this.followLinkButton}</div>}
<div className="documentButtonBar-button">{this.pinButton}</div>
<div className="documentButtonBar-button">{this.recordButton}</div>
- <div className="documentButtonBar-button">{this.calendarButton}</div>
<div className="documentButtonBar-button">{this.keywordButton}</div>
{!Doc.UserDoc().documentLinksButton_fullMenu ? null : <div className="documentButtonBar-button">{this.shareButton}</div>}
<div className="documentButtonBar-button">{this.menuButton}</div>
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index b11fa3bd5..2f6d1fbaa 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -192,21 +192,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;
diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx
index 0ac015b36..9574bd30e 100644
--- a/src/client/views/TagsView.tsx
+++ b/src/client/views/TagsView.tsx
@@ -9,7 +9,7 @@ import { emptyFunction } from '../../Utils';
import { Doc, DocListCast, Field, Opt, StrListCast } from '../../fields/Doc';
import { DocData } from '../../fields/DocSymbols';
import { List } from '../../fields/List';
-import { DocCast, NumCast, StrCast } from '../../fields/Types';
+import { DocCast, StrCast } from '../../fields/Types';
import { DocumentType } from '../documents/DocumentTypes';
import { DragManager } from '../util/DragManager';
import { SnappingManager } from '../util/SnappingManager';
@@ -216,7 +216,11 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
{metadata ? (
<span>
<b style={{ fontSize: 'smaller' }}>{tag}&nbsp;</b>
- {Field.toString(this._props.doc[metadata])}
+ {typeof this._props.doc[metadata] === 'boolean' ? (
+ <input type="checkbox" onClick={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()} onChange={e => (this._props.doc[metadata] = !this._props.doc[metadata])} checked={this._props.doc[metadata] as boolean} />
+ ) : (
+ Field.toString(this._props.doc[metadata])
+ )}
</span>
) : (
tag
@@ -266,7 +270,7 @@ export class TagsView extends ObservableReactComponent<TagViewProps> {
}
@computed get currentScale() {
- return NumCast(DocCast(this._props.View.Document.embedContainer)?._freeform_scale, 1);
+ return Math.max(1, 1 / this._props.View.screenToLocalScale());
}
@computed get isEditing() {
return this._isEditing && DocumentView.SelectedDocs().includes(this._props.View.Document);
@@ -283,15 +287,18 @@ export class TagsView extends ObservableReactComponent<TagViewProps> {
};
/**
- * 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]) {
+ TagItem.addTagToDoc(this._props.View.Document, '#' + submittedLabel[0]);
+ if (submittedLabel.length > 1) Doc.SetField(this._props.View.Document, submittedLabel[0].replace(/^@/, ''), ':' + submittedLabel[1]);
+ }
this._currentInput = ''; // Clear the input box
}),
'added doc label'
diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx
index 9eb16917b..30fd9fc2b 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
diff --git a/src/client/views/collections/CollectionCardDeckView.scss b/src/client/views/collections/CollectionCardDeckView.scss
index a089b248d..cc797d0bd 100644
--- a/src/client/views/collections/CollectionCardDeckView.scss
+++ b/src/client/views/collections/CollectionCardDeckView.scss
@@ -6,6 +6,15 @@
position: relative;
background-color: white;
overflow: hidden;
+
+ button {
+ width: 35px;
+ height: 35px;
+ border-radius: 50%;
+ background-color: $dark-gray;
+ // border-color: $medium-blue;
+ margin: 5px; // transform: translateY(-50px);
+ }
}
.card-wrapper {
@@ -34,15 +43,6 @@
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);
-}
-
// button:hover {
// transform: translateY(-50px);
// }
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/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
index f2f7f39bb..7a09ad9e2 100644
--- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
@@ -345,7 +345,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/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/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 73b20e6c2..a281479f1 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -2117,7 +2117,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}
@@ -2136,7 +2135,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}>