diff --git a/backend/chainlit/translations/en-US.json b/backend/chainlit/translations/en-US.json index 5cc8afa9fe..37a4806569 100644 --- a/backend/chainlit/translations/en-US.json +++ b/backend/chainlit/translations/en-US.json @@ -57,7 +57,7 @@ }, "chat": { "input": { - "placeholder": "Type your message here...", + "placeholder": "Your input...", "actions": { "send": "Send message", "stop": "Stop Task", diff --git a/frontend/package.json b/frontend/package.json index e9ed7df955..13c349dc37 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -33,6 +33,7 @@ "@radix-ui/react-slider": "^1.2.2", "@radix-ui/react-slot": "^1.1.1", "@radix-ui/react-switch": "^1.1.2", + "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-tooltip": "^1.1.6", "@tanstack/react-table": "^8.20.6", "class-variance-authority": "^0.7.1", @@ -41,8 +42,12 @@ "embla-carousel-react": "^8.5.1", "highlight.js": "^11.9.0", "i18next": "^23.7.16", + "js-base64": "^3.7.7", + "js-cookie": "^3.0.5", "lodash": "^4.17.21", "lucide-react": "^0.468.0", + "mermaid": "^11.4.1", + "pako": "^2.1.0", "plotly.js": "^2.27.0", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -58,6 +63,7 @@ "react-resizable-panels": "^2.1.7", "react-router-dom": "^6.15.0", "react-runner": "^1.0.5", + "react-vega": "^7.6.0", "recoil": "^0.7.7", "rehype-katex": "^7.0.0", "rehype-raw": "^7.0.0", @@ -90,7 +96,7 @@ "autoprefixer": "^10.4.20", "immutable": "^4.3.4", "jsdom": "^22.1.0", - "postcss": "^8.4.49", + "postcss": "^8.5.1", "tailwindcss": "^3.4.16", "tslib": "^2.6.2", "typescript": "^5.2.2", @@ -115,6 +121,10 @@ "rollup@>=3.0.0 <3.29.5": ">=3.29.5", "rollup@>=4.0.0 <4.22.4": ">=4.22.4", "cross-spawn@>=7.0.0 <7.0.5": ">=7.0.5" - } + } + }, + "peerDependencies": { + "@chainlit/copilot": "workspace:^", + "@evoya/file-picker": "workspace:^" } } diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 1a3cbf3cd4..496e949aa7 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -24,9 +24,15 @@ importers: .: dependencies: + '@chainlit/copilot': + specifier: workspace:^ + version: link:../libs/copilot '@chainlit/react-client': specifier: workspace:^ version: link:../libs/react-client + '@evoya/file-picker': + specifier: workspace:^ + version: link:../libs/evoya-files '@hookform/resolvers': specifier: ^3.9.1 version: 3.9.1(react-hook-form@7.54.2(react@18.3.1)) @@ -81,6 +87,9 @@ importers: '@radix-ui/react-switch': specifier: ^1.1.2 version: 1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-tabs': + specifier: ^1.1.13 + version: 1.1.13(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-tooltip': specifier: ^1.1.6 version: 1.1.6(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -105,12 +114,24 @@ importers: i18next: specifier: ^23.7.16 version: 23.7.16 + js-base64: + specifier: ^3.7.7 + version: 3.7.7 + js-cookie: + specifier: ^3.0.5 + version: 3.0.5 lodash: specifier: ^4.17.21 version: 4.17.21 lucide-react: specifier: ^0.468.0 version: 0.468.0(react@18.3.1) + mermaid: + specifier: ^11.4.1 + version: 11.4.1 + pako: + specifier: ^2.1.0 + version: 2.1.0 plotly.js: specifier: ^2.27.0 version: 2.30.1(mapbox-gl@1.13.3) @@ -156,6 +177,9 @@ importers: react-runner: specifier: ^1.0.5 version: 1.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-vega: + specifier: ^7.6.0 + version: 7.6.0(react@18.3.1)(vega-lite@5.23.0(vega@5.31.0))(vega@5.31.0) recoil: specifier: ^0.7.7 version: 0.7.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -240,7 +264,7 @@ importers: version: 3.3.2(vite@5.4.14(@types/node@20.5.7)) autoprefixer: specifier: ^10.4.20 - version: 10.4.20(postcss@8.4.49) + version: 10.4.20(postcss@8.5.1) immutable: specifier: ^4.3.4 version: 4.3.5 @@ -248,8 +272,8 @@ importers: specifier: ^22.1.0 version: 22.1.0 postcss: - specifier: ^8.4.49 - version: 8.4.49 + specifier: ^8.5.1 + version: 8.5.1 tailwindcss: specifier: ^3.4.16 version: 3.4.16 @@ -285,6 +309,12 @@ packages: resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} engines: {node: '>=6.0.0'} + '@antfu/install-pkg@1.0.0': + resolution: {integrity: sha512-xvX6P/lo1B3ej0OsaErAjqgFYzYVcJpamjLAFLYh9vRJngBrMoUG7aVnrGTeqM7yxbyTD5p3F2+0/QUEh8Vzhw==} + + '@antfu/utils@8.1.0': + resolution: {integrity: sha512-XPR7Jfwp0FFl/dFYPX8ZjpmU4/1mIXTjnZ1ba48BLMyKOV62/tiRjdsFcPs2hsYcSud4tzk7w3a3LjX8Fu3huA==} + '@babel/code-frame@7.23.5': resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} engines: {node: '>=6.9.0'} @@ -400,6 +430,24 @@ packages: resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==} engines: {node: '>=6.9.0'} + '@braintree/sanitize-url@7.1.1': + resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==} + + '@chevrotain/cst-dts-gen@11.0.3': + resolution: {integrity: sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==} + + '@chevrotain/gast@11.0.3': + resolution: {integrity: sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==} + + '@chevrotain/regexp-to-ast@11.0.3': + resolution: {integrity: sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==} + + '@chevrotain/types@11.0.3': + resolution: {integrity: sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==} + + '@chevrotain/utils@11.0.3': + resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==} + '@choojs/findup@0.2.1': resolution: {integrity: sha512-YstAqNb0MCN8PjdLCDfRsBcGVRN41f3vgLvaI0IrIcBp4AqILRSS0DeWNGkicC+f/zRIPJLc+9RURVSepwvfBw==} hasBin: true @@ -562,6 +610,12 @@ packages: peerDependencies: react-hook-form: ^7.0.0 + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@2.3.0': + resolution: {integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -628,6 +682,9 @@ packages: resolution: {integrity: sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==} engines: {node: '>=6.0.0'} + '@mermaid-js/parser@0.3.0': + resolution: {integrity: sha512-HsvL6zgE5sUPGgkIDlmAWR1HTNHz2Iy11BAWPTa4Jjabkpguy4Ze2gzfLrg6pdRuBvFwgUYyxiaNqZwrEEXepA==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -672,6 +729,9 @@ packages: '@radix-ui/primitive@1.1.1': resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==} + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + '@radix-ui/react-accordion@1.2.2': resolution: {integrity: sha512-b1oh54x4DMCdGsB4/7ahiSrViXxaBwRPotiZNnYXjLha9vfuURSAZErki6qjDoSIV0eXx5v57XnTGVtGwnfp2g==} peerDependencies: @@ -776,6 +836,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-compose-refs@1.0.1': resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} peerDependencies: @@ -794,6 +867,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-context@1.0.1': resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} peerDependencies: @@ -812,6 +894,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-dialog@1.0.5': resolution: {integrity: sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==} peerDependencies: @@ -847,6 +938,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-dismissable-layer@1.0.5': resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==} peerDependencies: @@ -961,6 +1061,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-label@2.1.1': resolution: {integrity: sha512-UUw5E4e/2+4kFMH7+YxORXGWggtY6sM8WIwh5RZchhLuUg2H1hc98Py+pr8HMz6rdaYrK2t296ZEjYLOCO5uUw==} peerDependencies: @@ -1065,6 +1174,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-primitive@1.0.3': resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} peerDependencies: @@ -1091,6 +1213,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-progress@1.1.1': resolution: {integrity: sha512-6diOawA84f/eMxFHcWut0aE1C2kyE9dOyCTQOMRR2C/qPiXz/X0SaiA/RLbapQaXUCmy0/hLMf9meSccD1N0pA==} peerDependencies: @@ -1117,6 +1252,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-roving-focus@1.1.11': + resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-scroll-area@1.2.2': resolution: {integrity: sha512-EFI1N/S3YxZEW/lJ/H1jY3njlvTd8tBmgKEn4GHi51+aMm94i6NmAJstsm5cu3yJwYqYc93gpCPm21FeAbFk6g==} peerDependencies: @@ -1187,6 +1335,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-switch@1.1.2': resolution: {integrity: sha512-zGukiWHjEdBCRyXvKR6iXAQG6qXm2esuAD6kDOi9Cn+1X6ev3ASo4+CsYaD6Fov9r/AQFekqnD/7+V0Cs6/98g==} peerDependencies: @@ -1200,6 +1357,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-tabs@1.1.13': + resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-tooltip@1.1.6': resolution: {integrity: sha512-TLB5D8QLExS1uDn7+wH/bjEmRurNMTzNrtq7IjaS4kjion9NtzsTGkvR5+i7yc9q01Pi2KMM2cN3f8UG4IvvXA==} peerDependencies: @@ -1231,6 +1401,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-controllable-state@1.0.1': resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} peerDependencies: @@ -1249,6 +1428,24 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-escape-keydown@1.0.3': resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} peerDependencies: @@ -1285,6 +1482,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-previous@1.1.0': resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==} peerDependencies: @@ -1642,6 +1848,99 @@ packages: '@types/chai@4.3.13': resolution: {integrity: sha512-+LxQEbg4BDUf88utmhpUpTyYn1zHao443aGnXIAQak9ZMt9Rtsic0Oig0OS1xyIqdDXc5uMekoC6NaiUlkT/qA==} + '@types/d3-array@3.2.1': + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.6': + resolution: {integrity: sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.7': + resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} @@ -1657,6 +1956,9 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/geojson@7946.0.4': + resolution: {integrity: sha512-MHmwBtCb7OCv1DSivz2UNJXPGU/1btAWRKlqJ2saEhVJkpkvqHMMaOpKg0v4sAbDWSQekHGvPVMM8nQ+Jen03Q==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -1719,6 +2021,9 @@ packages: '@types/testing-library__jest-dom@5.14.9': resolution: {integrity: sha512-FSYhIjFlfOpGSRyVoMBMuS3ws5ehFQODymf3vlI7U1K8c7PHwWwFY7VREfmsuzHSOnoKs/9/Y983ayOs7eRzqw==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.10': resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} @@ -1784,6 +2089,11 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -1988,6 +2298,14 @@ packages: check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + chevrotain-allstar@0.3.1: + resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==} + peerDependencies: + chevrotain: ^11.0.0 + + chevrotain@11.0.3: + resolution: {integrity: sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -2005,6 +2323,10 @@ packages: client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + clsx@1.2.1: resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} engines: {node: '>=6'} @@ -2070,6 +2392,10 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + commander@8.3.0: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} @@ -2078,12 +2404,21 @@ packages: resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} engines: {'0': node >= 0.8} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cose-base@1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + + cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + cosmiconfig@8.3.6: resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} engines: {node: '>=14'} @@ -2139,9 +2474,39 @@ packages: csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + cytoscape-cose-bilkent@4.1.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape-fcose@2.2.0: + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape@3.31.0: + resolution: {integrity: sha512-zDGn1K/tfZwEnoGOcHc0H4XazqAAXAuDpcYw9mUnUjATjqljyCNGJv8uEvbvxGaGHaVshxMecyl6oc6uKzRfbw==} + engines: {node: '>=0.10'} + d3-array@1.2.4: resolution: {integrity: sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==} + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + d3-collection@1.0.7: resolution: {integrity: sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==} @@ -2149,25 +2514,75 @@ packages: resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} engines: {node: '>=12'} + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + d3-dispatch@1.0.6: resolution: {integrity: sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==} + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + d3-force@1.2.1: resolution: {integrity: sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==} + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + d3-format@1.4.5: resolution: {integrity: sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==} + d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + d3-geo-projection@2.9.0: resolution: {integrity: sha512-ZULvK/zBn87of5rWAfFMc9mJOipeSo57O+BBitsKIXmU4rTVAnX1kSsJkE0R+TxY8pGNoM1nbyRRE7GYHhdOEQ==} hasBin: true + d3-geo-projection@4.0.0: + resolution: {integrity: sha512-p0bK60CEzph1iqmnxut7d/1kyTmm3UWtPlwdkM31AU+LW+BXazd5zJdoCn7VFxNCHXRngPHRnsNn5uGjLRGndg==} + engines: {node: '>=12'} + hasBin: true + d3-geo@1.12.1: resolution: {integrity: sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==} + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + d3-hierarchy@1.1.9: resolution: {integrity: sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==} + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + d3-interpolate@3.0.1: resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} engines: {node: '>=12'} @@ -2175,29 +2590,96 @@ packages: d3-path@1.0.9: resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + d3-quadtree@1.0.7: resolution: {integrity: sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA==} + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + d3-shape@1.3.7: resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + d3-time-format@2.3.0: resolution: {integrity: sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==} + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + d3-time@1.1.0: resolution: {integrity: sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==} + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + d3-timer@1.0.10: resolution: {integrity: sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==} + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + d@1.0.2: resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} engines: {node: '>=0.12'} + dagre-d3-es@7.0.11: + resolution: {integrity: sha512-tvlJLyQf834SylNKax8Wkzco/1ias1OPw8DcUMDE7oUIoSEW25riQVuiu/0OWEFqT0cxHT3Pa9/D82Jr47IONw==} + data-urls@4.0.0: resolution: {integrity: sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==} engines: {node: '>=14'} + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -2223,6 +2705,15 @@ packages: supports-color: optional: true + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} @@ -2252,6 +2743,9 @@ packages: defined@1.0.1: resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==} + delaunator@5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -2287,6 +2781,9 @@ packages: engines: {node: '>=12'} deprecated: Use your platform's native DOMException instead + dompurify@3.2.4: + resolution: {integrity: sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==} + dot-case@3.0.4: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} @@ -2449,6 +2946,9 @@ packages: resolution: {integrity: sha512-HuC1qF9iTnHDnML9YZAdCDQwT0yKl/U55K4XSUXqGAA2GLoafFgWRqdAbhWJxXaYD4pyoVxAJ8wH670jMpI9DQ==} engines: {node: '>=0.4.0'} + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -2456,6 +2956,9 @@ packages: fast-isnumeric@1.1.4: resolution: {integrity: sha512-1mM8qOr2LYz8zGaUdmiqRDiuue00Dxjgcb1NQR7TnhLVh6sQyngP9xvLo7Sl7LZpP/sk5eb+bcyWXw530NTBZw==} + fast-json-patch@3.1.1: + resolution: {integrity: sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==} + fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} @@ -2511,6 +3014,10 @@ packages: geojson-vt@3.2.1: resolution: {integrity: sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==} + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + get-canvas-context@1.0.2: resolution: {integrity: sha512-LnpfLf/TNzr9zVOGiIY6aKCz8EKuXmlYNV7CM2pUjBa/B+c2I15tS7KLySep75+FuerJdmArvJLcsAXWEy2H0A==} @@ -2558,6 +3065,10 @@ packages: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} + globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} @@ -2616,6 +3127,9 @@ packages: grid-index@1.1.0: resolution: {integrity: sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==} + hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + hamt_plus@1.0.2: resolution: {integrity: sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==} @@ -2758,6 +3272,10 @@ packages: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + is-alphabetical@2.0.1: resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} @@ -2934,6 +3452,13 @@ packages: resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} hasBin: true + js-base64@3.7.7: + resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} + + js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2958,6 +3483,9 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-stringify-pretty-compact@4.0.0: + resolution: {integrity: sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==} + json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -2973,6 +3501,22 @@ packages: kdbush@3.0.0: resolution: {integrity: sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==} + khroma@2.1.0: + resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} + + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + + langium@3.0.0: + resolution: {integrity: sha512-+Ez9EoiByeoTu/2BXmEaZ06iPNXM6thWJp02KfBO/raSMyCJ4jw7AkWWa+zBCTm0+Tw1Fj9FOxdqSskyN5nAwg==} + engines: {node: '>=16.0.0'} + + layout-base@1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + + layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + lilconfig@3.1.1: resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==} engines: {node: '>=14'} @@ -2991,6 +3535,13 @@ packages: resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} engines: {node: '>=14'} + local-pkg@1.0.0: + resolution: {integrity: sha512-bbgPw/wmroJsil/GgL4qjDzs5YLTBMQ99weRsok1XCDccQeehbHA/I1oRvk2NPtr7KGZgT/Y5tPRnAtMqeG2Kg==} + engines: {node: '>=14'} + + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -3043,6 +3594,11 @@ packages: markdown-table@3.0.3: resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} + marked@13.0.3: + resolution: {integrity: sha512-rqRix3/TWzE9rIoFGIn8JmsVfhiuC8VIQ8IdX5TfzmeBucdY05/0UlzKaw0eVtpcN/OdVFpBk7CjKGo9iHJ/zA==} + engines: {node: '>= 18'} + hasBin: true + math-log2@1.0.1: resolution: {integrity: sha512-9W0yGtkaMAkf74XGYVy4Dqw3YUMnTNB2eeiw9aQbUl4A3KmuCEHTt2DgAB07ENzOYAjsYSAYufkAq0Zd+jU7zA==} engines: {node: '>=0.10.0'} @@ -3105,6 +3661,9 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + mermaid@11.4.1: + resolution: {integrity: sha512-Mb01JT/x6CKDWaxigwfZYuYmDZ6xtrNwNlidKZwkSrDaY9n90tdrJTV5Umk+wP1fZscGptmKFXHsXMDEVZ+Q6A==} + micromark-core-commonmark@2.0.0: resolution: {integrity: sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==} @@ -3225,6 +3784,9 @@ packages: mlly@1.6.1: resolution: {integrity: sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==} + mlly@1.7.4: + resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + mouse-change@1.4.0: resolution: {integrity: sha512-vpN0s+zLL2ykyyUDh+fayu9Xkor5v/zRD9jhSqjRS1cJTGS0+oakVZzNm5n19JvvEj0you+MXlYTpNxUDQUjkQ==} @@ -3243,6 +3805,9 @@ packages: ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mumath@3.3.4: resolution: {integrity: sha512-VAFIOG6rsxoc7q/IaY3jdjmrsuX9f15KlRLYTHmixASBZkZEKC1IFqE2BC5CdhXmK6WLM1Re33z//AGmeRI6FA==} deprecated: Redundant dependency in your project. @@ -3272,6 +3837,15 @@ packages: no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} @@ -3332,6 +3906,12 @@ packages: resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + package-manager-detector@0.2.9: + resolution: {integrity: sha512-+vYvA/Y31l8Zk8dwxHhL3JfTuHPm6tlxM2A3GeQyl7ovYnSp1+mzAxClxaOr0qO1TtPxbQxetI7v5XqKLJZk7Q==} + + pako@2.1.0: + resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -3358,6 +3938,9 @@ packages: parse5@7.1.2: resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -3376,6 +3959,9 @@ packages: pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} @@ -3417,12 +4003,21 @@ packages: pkg-types@1.0.3: resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + plotly.js@2.30.1: resolution: {integrity: sha512-KE3KeM4B6qtjPU7FGOxklmwYua4nWGgr48BRMWZVysZjphlSaQLzvUAieFlUCfPBPfJIRBLxFQy1KHMIQgfwrA==} point-in-polygon@1.1.0: resolution: {integrity: sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw==} + points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + + points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + polybooljs@1.2.2: resolution: {integrity: sha512-ziHW/02J0XuNuUtmidBc6GXE8YohYydp3DWPWXYsd7O721TjcmN+k6ezjdwkDqep+gnWnFY+yqZHvzElra2oCg==} @@ -3467,8 +4062,8 @@ packages: postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.4.49: - resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + postcss@8.5.1: + resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==} engines: {node: ^10 || ^12 || >=14} potpack@1.0.2: @@ -3667,6 +4262,13 @@ packages: '@types/react': optional: true + react-vega@7.6.0: + resolution: {integrity: sha512-2oMML4wH9qWLnZPRxJm06ozwrVN/K+nkjqdI5/ofWWsrBnnH4iB9rRKrsV8px0nlWgZrwfdCH4g5RUiyyJHWSA==} + peerDependencies: + react: ^16 || ^17 || ^18 + vega: '*' + vega-lite: '*' + react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -3746,6 +4348,10 @@ packages: remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} @@ -3770,11 +4376,17 @@ packages: right-now@1.0.0: resolution: {integrity: sha512-DA8+YS+sMIVpbsuKgy+Z67L9Lxb1p05mNxRpDPNksPDEFir4vmBlUtuN9jkTGn9YMMdlBuK7XQgFiz6ws+yhSg==} + robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + rollup@4.31.0: resolution: {integrity: sha512-9cCE8P4rZLx9+PjoyqHLs31V9a9Vpvfo4qNcs6JCiGWYhw2gijSetFbH6SSy1whnkgcefnUwr8sad7tgqsGvnw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + rrweb-cssom@0.6.0: resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} @@ -3807,6 +4419,11 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true + semver@7.7.1: + resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} + engines: {node: '>=10'} + hasBin: true + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -3931,6 +4548,9 @@ packages: style-to-object@1.0.5: resolution: {integrity: sha512-rDRwHtoDD3UMMrmZ6BzOW0naTjMsVZLIjsGleSKS/0Oz+cgCfAPRspaqJuE8rDzpKha/nEvnM0IF4seEAZUTKQ==} + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} @@ -4006,6 +4626,9 @@ packages: tinycolor2@1.6.0: resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinypool@0.7.0: resolution: {integrity: sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==} engines: {node: '>=14.0.0'} @@ -4039,6 +4662,9 @@ packages: resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} engines: {node: '>=6'} + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tr46@4.1.1: resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==} engines: {node: '>=14'} @@ -4049,6 +4675,10 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-dedent@2.2.0: + resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} + engines: {node: '>=6.10'} + ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} @@ -4065,6 +4695,9 @@ packages: tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + type-detect@4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} @@ -4086,6 +4719,9 @@ packages: ufo@1.5.2: resolution: {integrity: sha512-eiutMaL0J2MKdhcOM1tUy13pIrYnyR87fEd8STJQFrrAwImwvlXkxlZEjaKah8r2viPohld08lt73QfLG1NxMg==} + ufo@1.5.4: + resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -4174,6 +4810,128 @@ packages: resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} hasBin: true + uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true + + vega-canvas@1.2.7: + resolution: {integrity: sha512-OkJ9CACVcN9R5Pi9uF6MZBF06pO6qFpDYHWSKBJsdHP5o724KrsgR6UvbnXFH82FdsiTOff/HqjuaG8C7FL+9Q==} + + vega-crossfilter@4.1.3: + resolution: {integrity: sha512-nyPJAXAUABc3EocUXvAL1J/IWotZVsApIcvOeZaUdEQEtZ7bt8VtP2nj3CLbHBA8FZZVV+K6SmdwvCOaAD4wFQ==} + + vega-dataflow@5.7.7: + resolution: {integrity: sha512-R2NX2HvgXL+u4E6u+L5lKvvRiCtnE6N6l+umgojfi53suhhkFP+zB+2UAQo4syxuZ4763H1csfkKc4xpqLzKnw==} + + vega-embed@6.29.0: + resolution: {integrity: sha512-PmlshTLtLFLgWtF/b23T1OwX53AugJ9RZ3qPE2c01VFAbgt3/GSNI/etzA/GzdrkceXFma+FDHNXUppKuM0U6Q==} + peerDependencies: + vega: ^5.21.0 + vega-lite: '*' + + vega-encode@4.10.2: + resolution: {integrity: sha512-fsjEY1VaBAmqwt7Jlpz0dpPtfQFiBdP9igEefvumSpy7XUxOJmDQcRDnT3Qh9ctkv3itfPfI9g8FSnGcv2b4jQ==} + + vega-event-selector@3.0.1: + resolution: {integrity: sha512-K5zd7s5tjr1LiOOkjGpcVls8GsH/f2CWCrWcpKy74gTCp+llCdwz0Enqo013ZlGaRNjfgD/o1caJRt3GSaec4A==} + + vega-expression@5.1.2: + resolution: {integrity: sha512-fFeDTh4UtOxlZWL54jf1ZqJHinyerWq/ROiqrQxqLkNJRJ86RmxYTgXwt65UoZ/l4VUv9eAd2qoJeDEf610Umw==} + + vega-force@4.2.2: + resolution: {integrity: sha512-cHZVaY2VNNIG2RyihhSiWniPd2W9R9kJq0znxzV602CgUVgxEfTKtx/lxnVCn8nNrdKAYrGiqIsBzIeKG1GWHw==} + + vega-format@1.1.3: + resolution: {integrity: sha512-wQhw7KR46wKJAip28FF/CicW+oiJaPAwMKdrxlnTA0Nv8Bf7bloRlc+O3kON4b4H1iALLr9KgRcYTOeXNs2MOA==} + + vega-functions@5.16.0: + resolution: {integrity: sha512-uXjSDbbGcFLCQTZZI+OiZK0U+2dLWC26ONdO0g9RhPzXXzR3niPcFOA0bc/OeiHdTexqsLjOiXxR/K2BckB8gQ==} + + vega-geo@4.4.3: + resolution: {integrity: sha512-+WnnzEPKIU1/xTFUK3EMu2htN35gp9usNZcC0ZFg2up1/Vqu6JyZsX0PIO51oXSIeXn9bwk6VgzlOmJUcx92tA==} + + vega-hierarchy@4.1.3: + resolution: {integrity: sha512-0Z+TYKRgOEo8XYXnJc2HWg1EGpcbNAhJ9Wpi9ubIbEyEHqIgjCIyFVN8d4nSfsJOcWDzsSmRqohBztxAhOCSaw==} + + vega-interpreter@1.1.0: + resolution: {integrity: sha512-5iytKMUfPTEnC6x8huPIYCqyDdBcMcPYwE+RvAOyqFXBgepDPVGkcyHhePOZ/Dp1jTAuqVlx7o64qt0ZR6ij+w==} + + vega-label@1.3.1: + resolution: {integrity: sha512-Emx4b5s7pvuRj3fBkAJ/E2snCoZACfKAwxVId7f/4kYVlAYLb5Swq6W8KZHrH4M9Qds1XJRUYW9/Y3cceqzEFA==} + + vega-lite@5.23.0: + resolution: {integrity: sha512-l4J6+AWE3DIjvovEoHl2LdtCUkfm4zs8Xxx7INwZEAv+XVb6kR6vIN1gt3t2gN2gs/y4DYTs/RPoTeYAuEg6mA==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + vega: ^5.24.0 + + vega-loader@4.5.3: + resolution: {integrity: sha512-dUfIpxTLF2magoMaur+jXGvwMxjtdlDZaIS8lFj6N7IhUST6nIvBzuUlRM+zLYepI5GHtCLOnqdKU4XV0NggCA==} + + vega-parser@6.4.1: + resolution: {integrity: sha512-ZjF5aQfRe3yD5e2zYZcWWkUn9zGzUonMIirWTp3S3UBCujz+aT0+Ls6wbHdAH6hCPj3PVVkSWuuLkGEIUpWqyQ==} + + vega-projection@1.6.2: + resolution: {integrity: sha512-3pcVaQL9R3Zfk6PzopLX6awzrQUeYOXJzlfLGP2Xd93mqUepBa6m/reVrTUoSFXA3v9lfK4W/PS2AcVzD/MIcQ==} + + vega-regression@1.3.1: + resolution: {integrity: sha512-AmccF++Z9uw4HNZC/gmkQGe6JsRxTG/R4QpbcSepyMvQN1Rj5KtVqMcmVFP1r3ivM4dYGFuPlzMWvuqp0iKMkQ==} + + vega-runtime@6.2.1: + resolution: {integrity: sha512-b4eot3tWKCk++INWqot+6sLn3wDTj/HE+tRSbiaf8aecuniPMlwJEK7wWuhVGeW2Ae5n8fI/8TeTViaC94bNHA==} + + vega-scale@7.4.2: + resolution: {integrity: sha512-o6Hl76aU1jlCK7Q8DPYZ8OGsp4PtzLdzI6nGpLt8rxoE78QuB3GBGEwGAQJitp4IF7Lb2rL5oAXEl3ZP6xf9jg==} + + vega-scenegraph@4.13.1: + resolution: {integrity: sha512-LFY9+sLIxRfdDI9ZTKjLoijMkIAzPLBWHpPkwv4NPYgdyx+0qFmv+puBpAUGUY9VZqAZ736Uj5NJY9zw+/M3yQ==} + + vega-schema-url-parser@2.2.0: + resolution: {integrity: sha512-yAtdBnfYOhECv9YC70H2gEiqfIbVkq09aaE4y/9V/ovEFmH9gPKaEgzIZqgT7PSPQjKhsNkb6jk6XvSoboxOBw==} + + vega-selections@5.5.0: + resolution: {integrity: sha512-TkpklUg9yhKjnTEs3Ls0eSI2aMJ8+tRicrFAKlDyrEBNMSSEaMsSJ84Ro5xpRra+GMBkGXFYgwTPC7y3tj20Gg==} + + vega-statistics@1.9.0: + resolution: {integrity: sha512-GAqS7mkatpXcMCQKWtFu1eMUKLUymjInU0O8kXshWaQrVWjPIO2lllZ1VNhdgE0qGj4oOIRRS11kzuijLshGXQ==} + + vega-themes@2.15.0: + resolution: {integrity: sha512-DicRAKG9z+23A+rH/3w3QjJvKnlGhSbbUXGjBvYGseZ1lvj9KQ0BXZ2NS/+MKns59LNpFNHGi9us/wMlci4TOA==} + peerDependencies: + vega: '*' + vega-lite: '*' + + vega-time@2.1.3: + resolution: {integrity: sha512-hFcWPdTV844IiY0m97+WUoMLADCp+8yUQR1NStWhzBzwDDA7QEGGwYGxALhdMOaDTwkyoNj3V/nox2rQAJD/vQ==} + + vega-tooltip@0.35.2: + resolution: {integrity: sha512-kuYcsAAKYn39ye5wKf2fq1BAxVcjoz0alvKp/G+7BWfIb94J0PHmwrJ5+okGefeStZnbXxINZEOKo7INHaj9GA==} + + vega-transforms@4.12.1: + resolution: {integrity: sha512-Qxo+xeEEftY1jYyKgzOGc9NuW4/MqGm1YPZ5WrL9eXg2G0410Ne+xL/MFIjHF4hRX+3mgFF4Io2hPpfy/thjLg==} + + vega-typings@1.4.0: + resolution: {integrity: sha512-UTXjuasq0Q8uMuzz/qow4moVHFJ5atYdQu871QZJ/zgWY3Po4du3dIGBVQN4fYEv6seKhDvxpEFke2rqx81Wqw==} + + vega-util@1.17.3: + resolution: {integrity: sha512-nSNpZLUrRvFo46M5OK4O6x6f08WD1yOcEzHNlqivF+sDLSsVpstaF6fdJYwrbf/debFi2L9Tkp4gZQtssup9iQ==} + + vega-view-transforms@4.6.1: + resolution: {integrity: sha512-RYlyMJu5kZV4XXjmyTQKADJWDB25SMHsiF+B1rbE1p+pmdQPlp5tGdPl9r5dUJOp3p8mSt/NGI8GPGucmPMxtw==} + + vega-view@5.14.0: + resolution: {integrity: sha512-gg2ukCviKG6Nofmr0Y6hFbr9romRMzmXHe3ljNJ5QyRnkwmQ7HbTvXOyS9cZZ0VtuhSRw+uiyd0Pg+nep0IhwA==} + + vega-voronoi@4.2.4: + resolution: {integrity: sha512-lWNimgJAXGeRFu2Pz8axOUqVf1moYhD+5yhBzDSmckE9I5jLOyZc/XvgFTXwFnsVkMd1QW1vxJa+y9yfUblzYw==} + + vega-wordcloud@4.1.6: + resolution: {integrity: sha512-lFmF3u9/ozU0P+WqPjeThQfZm0PigdbXDwpIUCxczrCXKYJLYFmZuZLZR7cxtmpZ0/yuvRvAJ4g123LXbSZF8A==} + + vega@5.31.0: + resolution: {integrity: sha512-ZZ+8kcKqCeRi7pBdS7kfBpfhV2gDpa6N950GKGWFw0QL4fH319A9o8FAJzdY8zK0WW0PKrivZSoRmK9fWUxnhg==} + vfile-location@5.0.2: resolution: {integrity: sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg==} @@ -4267,6 +5025,26 @@ packages: resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} engines: {node: '>=0.10.0'} + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-uri@3.0.8: + resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + vt-pbf@3.1.3: resolution: {integrity: sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==} @@ -4283,6 +5061,9 @@ packages: webgl-context@2.2.0: resolution: {integrity: sha512-q/fGIivtqTT7PEoF07axFIlHNk/XCPaYpq64btnepopSWvKNFkoORlQYgqDigBIuGA1ExnFd/GnSUnBNEPQY7Q==} + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webidl-conversions@7.0.0: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} @@ -4299,6 +5080,9 @@ packages: resolution: {integrity: sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==} engines: {node: '>=14'} + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} @@ -4361,6 +5145,10 @@ packages: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -4369,6 +5157,14 @@ packages: engines: {node: '>= 14'} hasBin: true + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + yocto-queue@1.0.0: resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} engines: {node: '>=12.20'} @@ -4390,6 +5186,13 @@ snapshots: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.21 + '@antfu/install-pkg@1.0.0': + dependencies: + package-manager-detector: 0.2.9 + tinyexec: 0.3.2 + + '@antfu/utils@8.1.0': {} + '@babel/code-frame@7.23.5': dependencies: '@babel/highlight': 7.23.4 @@ -4541,6 +5344,25 @@ snapshots: '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 + '@braintree/sanitize-url@7.1.1': {} + + '@chevrotain/cst-dts-gen@11.0.3': + dependencies: + '@chevrotain/gast': 11.0.3 + '@chevrotain/types': 11.0.3 + lodash-es: 4.17.21 + + '@chevrotain/gast@11.0.3': + dependencies: + '@chevrotain/types': 11.0.3 + lodash-es: 4.17.21 + + '@chevrotain/regexp-to-ast@11.0.3': {} + + '@chevrotain/types@11.0.3': {} + + '@chevrotain/utils@11.0.3': {} + '@choojs/findup@0.2.1': dependencies: commander: 2.20.3 @@ -4635,6 +5457,21 @@ snapshots: dependencies: react-hook-form: 7.54.2(react@18.3.1) + '@iconify/types@2.0.0': {} + + '@iconify/utils@2.3.0': + dependencies: + '@antfu/install-pkg': 1.0.0 + '@antfu/utils': 8.1.0 + '@iconify/types': 2.0.0 + debug: 4.4.0 + globals: 15.15.0 + kolorist: 1.8.0 + local-pkg: 1.0.0 + mlly: 1.7.4 + transitivePeerDependencies: + - supports-color + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -4703,6 +5540,10 @@ snapshots: '@mapbox/whoots-js@3.1.0': {} + '@mermaid-js/parser@0.3.0': + dependencies: + langium: 3.0.0 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4783,6 +5624,8 @@ snapshots: '@radix-ui/primitive@1.1.1': {} + '@radix-ui/primitive@1.1.3': {} + '@radix-ui/react-accordion@1.2.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.1 @@ -4888,6 +5731,18 @@ snapshots: '@types/react': 18.3.18 '@types/react-dom': 18.3.5(@types/react@18.3.18) + '@radix-ui/react-collection@1.1.7(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) + '@radix-ui/react-compose-refs@1.0.1(@types/react@18.3.18)(react@18.3.1)': dependencies: '@babel/runtime': 7.25.6 @@ -4901,6 +5756,12 @@ snapshots: optionalDependencies: '@types/react': 18.3.18 + '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.18)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + '@radix-ui/react-context@1.0.1(@types/react@18.3.18)(react@18.3.1)': dependencies: '@babel/runtime': 7.25.6 @@ -4914,6 +5775,12 @@ snapshots: optionalDependencies: '@types/react': 18.3.18 + '@radix-ui/react-context@1.1.2(@types/react@18.3.18)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + '@radix-ui/react-dialog@1.0.5(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.25.6 @@ -4965,6 +5832,12 @@ snapshots: optionalDependencies: '@types/react': 18.3.18 + '@radix-ui/react-direction@1.1.1(@types/react@18.3.18)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + '@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.25.6 @@ -5075,6 +5948,13 @@ snapshots: optionalDependencies: '@types/react': 18.3.18 + '@radix-ui/react-id@1.1.1(@types/react@18.3.18)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + '@radix-ui/react-label@2.1.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -5192,6 +6072,16 @@ snapshots: '@types/react': 18.3.18 '@types/react-dom': 18.3.5(@types/react@18.3.18) + '@radix-ui/react-presence@1.1.5(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) + '@radix-ui/react-primitive@1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.25.6 @@ -5211,6 +6101,15 @@ snapshots: '@types/react': 18.3.18 '@types/react-dom': 18.3.5(@types/react@18.3.18) + '@radix-ui/react-primitive@2.1.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) + '@radix-ui/react-progress@1.1.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-context': 1.1.1(@types/react@18.3.18)(react@18.3.1) @@ -5238,6 +6137,23 @@ snapshots: '@types/react': 18.3.18 '@types/react-dom': 18.3.5(@types/react@18.3.18) + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) + '@radix-ui/react-scroll-area@1.2.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/number': 1.1.0 @@ -5327,6 +6243,13 @@ snapshots: optionalDependencies: '@types/react': 18.3.18 + '@radix-ui/react-slot@1.2.3(@types/react@18.3.18)(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + '@radix-ui/react-switch@1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.1 @@ -5342,6 +6265,22 @@ snapshots: '@types/react': 18.3.18 '@types/react-dom': 18.3.5(@types/react@18.3.18) + '@radix-ui/react-tabs@1.1.13(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) + '@radix-ui/react-tooltip@1.1.6(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.1 @@ -5375,6 +6314,12 @@ snapshots: optionalDependencies: '@types/react': 18.3.18 + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.3.18)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + '@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.3.18)(react@18.3.1)': dependencies: '@babel/runtime': 7.25.6 @@ -5390,6 +6335,21 @@ snapshots: optionalDependencies: '@types/react': 18.3.18 + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@18.3.18)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@18.3.18)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + '@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.3.18)(react@18.3.1)': dependencies: '@babel/runtime': 7.25.6 @@ -5418,6 +6378,12 @@ snapshots: optionalDependencies: '@types/react': 18.3.18 + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@18.3.18)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + '@radix-ui/react-use-previous@1.1.0(@types/react@18.3.18)(react@18.3.1)': dependencies: react: 18.3.1 @@ -5725,6 +6691,123 @@ snapshots: '@types/chai@4.3.13': {} + '@types/d3-array@3.2.1': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.1 + '@types/geojson': 7946.0.4 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.6': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.4 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.7': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.6 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.7 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + '@types/debug@4.1.12': dependencies: '@types/ms': 0.7.34 @@ -5742,6 +6825,8 @@ snapshots: '@types/estree@1.0.6': {} + '@types/geojson@7946.0.4': {} + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.2 @@ -5810,6 +6895,9 @@ snapshots: dependencies: '@types/jest': 29.5.12 + '@types/trusted-types@2.0.7': + optional: true + '@types/unist@2.0.10': {} '@types/unist@3.0.2': {} @@ -5880,6 +6968,8 @@ snapshots: acorn@8.11.3: {} + acorn@8.14.0: {} + agent-base@6.0.2: dependencies: debug: 4.3.4 @@ -5950,14 +7040,14 @@ snapshots: attr-accept@2.2.2: {} - autoprefixer@10.4.20(postcss@8.4.49): + autoprefixer@10.4.20(postcss@8.5.1): dependencies: browserslist: 4.24.3 caniuse-lite: 1.0.30001688 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.0 - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.7: @@ -6071,6 +7161,20 @@ snapshots: dependencies: get-func-name: 2.0.2 + chevrotain-allstar@0.3.1(chevrotain@11.0.3): + dependencies: + chevrotain: 11.0.3 + lodash-es: 4.17.21 + + chevrotain@11.0.3: + dependencies: + '@chevrotain/cst-dts-gen': 11.0.3 + '@chevrotain/gast': 11.0.3 + '@chevrotain/regexp-to-ast': 11.0.3 + '@chevrotain/types': 11.0.3 + '@chevrotain/utils': 11.0.3 + lodash-es: 4.17.21 + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -6093,6 +7197,12 @@ snapshots: client-only@0.0.1: {} + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + clsx@1.2.1: {} clsx@2.1.1: {} @@ -6164,6 +7274,8 @@ snapshots: commander@4.1.1: {} + commander@7.2.0: {} + commander@8.3.0: {} concat-stream@1.6.2: @@ -6173,10 +7285,20 @@ snapshots: readable-stream: 2.3.8 typedarray: 0.0.6 + confbox@0.1.8: {} + convert-source-map@2.0.0: {} core-util-is@1.0.3: {} + cose-base@1.0.3: + dependencies: + layout-base: 1.0.2 + + cose-base@2.2.0: + dependencies: + layout-base: 2.0.1 + cosmiconfig@8.3.6(typescript@5.2.2): dependencies: import-fresh: 3.3.0 @@ -6230,14 +7352,71 @@ snapshots: csstype@3.1.2: {} + cytoscape-cose-bilkent@4.1.0(cytoscape@3.31.0): + dependencies: + cose-base: 1.0.3 + cytoscape: 3.31.0 + + cytoscape-fcose@2.2.0(cytoscape@3.31.0): + dependencies: + cose-base: 2.2.0 + cytoscape: 3.31.0 + + cytoscape@3.31.0: {} + d3-array@1.2.4: {} + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + d3-collection@1.0.7: {} d3-color@3.1.0: {} + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.0.1 + d3-dispatch@1.0.6: {} + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + d3-force@1.2.1: dependencies: d3-collection: 1.0.7 @@ -6245,8 +7424,16 @@ snapshots: d3-quadtree: 1.0.7 d3-timer: 1.0.10 + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + d3-format@1.4.5: {} + d3-format@3.1.0: {} + d3-geo-projection@2.9.0: dependencies: commander: 2.20.3 @@ -6254,43 +7441,154 @@ snapshots: d3-geo: 1.12.1 resolve: 1.22.8 + d3-geo-projection@4.0.0: + dependencies: + commander: 7.2.0 + d3-array: 3.2.4 + d3-geo: 3.1.1 + d3-geo@1.12.1: dependencies: d3-array: 1.2.4 + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + d3-hierarchy@1.1.9: {} + d3-hierarchy@3.1.2: {} + d3-interpolate@3.0.1: dependencies: d3-color: 3.1.0 d3-path@1.0.9: {} + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + d3-quadtree@1.0.7: {} + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 1.2.4 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + d3-shape@1.3.7: dependencies: d3-path: 1.0.9 + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + d3-time-format@2.3.0: dependencies: d3-time: 1.1.0 + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + d3-time@1.1.0: {} + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + d3-timer@1.0.10: {} + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.0 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + d@1.0.2: dependencies: es5-ext: 0.10.64 type: 2.7.2 + dagre-d3-es@7.0.11: + dependencies: + d3: 7.9.0 + lodash-es: 4.17.21 + data-urls@4.0.0: dependencies: abab: 2.0.6 whatwg-mimetype: 3.0.0 whatwg-url: 12.0.1 + dayjs@1.11.13: {} + debug@2.6.9: dependencies: ms: 2.0.0 @@ -6303,6 +7601,10 @@ snapshots: dependencies: ms: 2.1.2 + debug@4.4.0: + dependencies: + ms: 2.1.3 + decimal.js@10.4.3: {} decode-named-character-reference@1.0.2: @@ -6350,6 +7652,10 @@ snapshots: defined@1.0.1: {} + delaunator@5.0.1: + dependencies: + robust-predicates: 3.0.2 + delayed-stream@1.0.0: {} dequal@2.0.3: {} @@ -6374,6 +7680,10 @@ snapshots: dependencies: webidl-conversions: 7.0.0 + dompurify@3.2.4: + optionalDependencies: + '@types/trusted-types': 2.0.7 + dot-case@3.0.4: dependencies: no-case: 3.0.4 @@ -6565,6 +7875,8 @@ snapshots: acorn: 7.4.1 isarray: 2.0.5 + fast-deep-equal@3.1.3: {} + fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -6577,6 +7889,8 @@ snapshots: dependencies: is-string-blank: 1.0.1 + fast-json-patch@3.1.1: {} + fastq@1.17.1: dependencies: reusify: 1.0.4 @@ -6634,6 +7948,8 @@ snapshots: geojson-vt@3.2.1: {} + get-caller-file@2.0.5: {} + get-canvas-context@1.0.2: {} get-func-name@2.0.2: {} @@ -6702,6 +8018,8 @@ snapshots: globals@11.12.0: {} + globals@15.15.0: {} + globrex@0.1.2: {} glsl-inject-defines@1.0.3: @@ -6794,6 +8112,8 @@ snapshots: grid-index@1.1.0: {} + hachure-fill@0.5.2: {} + hamt_plus@1.0.2: {} has-bigints@1.0.2: {} @@ -6998,6 +8318,8 @@ snapshots: hasown: 2.0.0 side-channel: 1.0.6 + internmap@2.0.3: {} + is-alphabetical@2.0.1: {} is-alphanumerical@2.0.1: @@ -7161,6 +8483,10 @@ snapshots: jiti@1.21.6: {} + js-base64@3.7.7: {} + + js-cookie@3.0.5: {} + js-tokens@4.0.0: {} js-yaml@4.1.0: @@ -7201,6 +8527,8 @@ snapshots: json-parse-even-better-errors@2.3.1: {} + json-stringify-pretty-compact@4.0.0: {} + json5@2.2.3: {} jsonc-parser@3.2.1: {} @@ -7211,6 +8539,22 @@ snapshots: kdbush@3.0.0: {} + khroma@2.1.0: {} + + kolorist@1.8.0: {} + + langium@3.0.0: + dependencies: + chevrotain: 11.0.3 + chevrotain-allstar: 0.3.1(chevrotain@11.0.3) + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.0.8 + + layout-base@1.0.2: {} + + layout-base@2.0.1: {} + lilconfig@3.1.1: {} lilconfig@3.1.3: {} @@ -7221,6 +8565,13 @@ snapshots: local-pkg@0.4.3: {} + local-pkg@1.0.0: + dependencies: + mlly: 1.7.4 + pkg-types: 1.3.1 + + lodash-es@4.17.21: {} + lodash.merge@4.6.2: {} lodash.uniqueid@4.0.1: {} @@ -7288,6 +8639,8 @@ snapshots: markdown-table@3.0.3: {} + marked@13.0.3: {} + math-log2@1.0.1: {} mdast-util-directive@3.1.0: @@ -7473,6 +8826,31 @@ snapshots: merge2@1.4.1: {} + mermaid@11.4.1: + dependencies: + '@braintree/sanitize-url': 7.1.1 + '@iconify/utils': 2.3.0 + '@mermaid-js/parser': 0.3.0 + '@types/d3': 7.4.3 + cytoscape: 3.31.0 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.31.0) + cytoscape-fcose: 2.2.0(cytoscape@3.31.0) + d3: 7.9.0 + d3-sankey: 0.12.3 + dagre-d3-es: 7.0.11 + dayjs: 1.11.13 + dompurify: 3.2.4 + katex: 0.16.11 + khroma: 2.1.0 + lodash-es: 4.17.21 + marked: 13.0.3 + roughjs: 4.6.6 + stylis: 4.3.6 + ts-dedent: 2.2.0 + uuid: 9.0.1 + transitivePeerDependencies: + - supports-color + micromark-core-commonmark@2.0.0: dependencies: decode-named-character-reference: 1.0.2 @@ -7712,6 +9090,13 @@ snapshots: pkg-types: 1.0.3 ufo: 1.5.2 + mlly@1.7.4: + dependencies: + acorn: 8.14.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.5.4 + mouse-change@1.4.0: dependencies: mouse-event: 1.0.5 @@ -7730,6 +9115,8 @@ snapshots: ms@2.1.2: {} + ms@2.1.3: {} + mumath@3.3.4: dependencies: almost-equal: 1.1.0 @@ -7761,6 +9148,10 @@ snapshots: lower-case: 2.0.2 tslib: 2.6.2 + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + node-releases@2.0.14: {} node-releases@2.0.19: {} @@ -7813,6 +9204,10 @@ snapshots: dependencies: yocto-queue: 1.0.0 + package-manager-detector@0.2.9: {} + + pako@2.1.0: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -7849,6 +9244,8 @@ snapshots: dependencies: entities: 4.5.0 + path-data-parser@0.1.0: {} + path-key@3.1.1: {} path-parse@1.0.7: {} @@ -7862,6 +9259,8 @@ snapshots: pathe@1.1.2: {} + pathe@2.0.3: {} + pathval@1.1.1: {} pbf@3.2.1: @@ -7896,6 +9295,12 @@ snapshots: mlly: 1.6.1 pathe: 1.1.2 + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.7.4 + pathe: 2.0.3 + plotly.js@2.30.1(mapbox-gl@1.13.3): dependencies: '@plotly/d3': 3.8.1 @@ -7953,32 +9358,39 @@ snapshots: point-in-polygon@1.1.0: {} + points-on-curve@0.2.0: {} + + points-on-path@0.2.1: + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + polybooljs@1.2.2: {} possible-typed-array-names@1.0.0: {} - postcss-import@15.1.0(postcss@8.4.49): + postcss-import@15.1.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.8 - postcss-js@4.0.1(postcss@8.4.49): + postcss-js@4.0.1(postcss@8.5.1): dependencies: camelcase-css: 2.0.1 - postcss: 8.4.49 + postcss: 8.5.1 - postcss-load-config@4.0.2(postcss@8.4.49): + postcss-load-config@4.0.2(postcss@8.5.1): dependencies: lilconfig: 3.1.1 yaml: 2.4.1 optionalDependencies: - postcss: 8.4.49 + postcss: 8.5.1 - postcss-nested@6.2.0(postcss@8.4.49): + postcss-nested@6.2.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-selector-parser: 6.1.2 postcss-selector-parser@6.1.2: @@ -7988,7 +9400,7 @@ snapshots: postcss-value-parser@4.2.0: {} - postcss@8.4.49: + postcss@8.5.1: dependencies: nanoid: 3.3.8 picocolors: 1.1.1 @@ -8199,6 +9611,16 @@ snapshots: optionalDependencies: '@types/react': 18.3.18 + react-vega@7.6.0(react@18.3.1)(vega-lite@5.23.0(vega@5.31.0))(vega@5.31.0): + dependencies: + '@types/react': 18.3.18 + fast-deep-equal: 3.1.3 + prop-types: 15.8.1 + react: 18.3.1 + vega: 5.31.0 + vega-embed: 6.29.0(vega-lite@5.23.0(vega@5.31.0))(vega@5.31.0) + vega-lite: 5.23.0(vega@5.31.0) + react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -8372,6 +9794,8 @@ snapshots: mdast-util-to-markdown: 2.1.0 unified: 11.0.5 + require-directory@2.1.1: {} + requires-port@1.0.0: {} resolve-from@4.0.0: {} @@ -8392,6 +9816,8 @@ snapshots: right-now@1.0.0: {} + robust-predicates@3.0.2: {} + rollup@4.31.0: dependencies: '@types/estree': 1.0.6 @@ -8417,6 +9843,13 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.31.0 fsevents: 2.3.3 + roughjs@4.6.6: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + rrweb-cssom@0.6.0: {} run-parallel@1.2.0: @@ -8443,6 +9876,8 @@ snapshots: semver@6.3.1: {} + semver@7.7.1: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -8574,6 +10009,8 @@ snapshots: dependencies: inline-style-parser: 0.2.2 + stylis@4.3.6: {} + sucrase@3.35.0: dependencies: '@jridgewell/gen-mapping': 0.3.3 @@ -8649,11 +10086,11 @@ snapshots: normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.1.1 - postcss: 8.4.49 - postcss-import: 15.1.0(postcss@8.4.49) - postcss-js: 4.0.1(postcss@8.4.49) - postcss-load-config: 4.0.2(postcss@8.4.49) - postcss-nested: 6.2.0(postcss@8.4.49) + postcss: 8.5.1 + postcss-import: 15.1.0(postcss@8.5.1) + postcss-js: 4.0.1(postcss@8.5.1) + postcss-load-config: 4.0.2(postcss@8.5.1) + postcss-nested: 6.2.0(postcss@8.5.1) postcss-selector-parser: 6.1.2 resolve: 1.22.8 sucrase: 3.35.0 @@ -8682,6 +10119,8 @@ snapshots: tinycolor2@1.6.0: {} + tinyexec@0.3.2: {} + tinypool@0.7.0: {} tinyqueue@2.0.3: {} @@ -8711,6 +10150,8 @@ snapshots: universalify: 0.2.0 url-parse: 1.5.10 + tr46@0.0.3: {} + tr46@4.1.1: dependencies: punycode: 2.3.1 @@ -8719,6 +10160,8 @@ snapshots: trough@2.2.0: {} + ts-dedent@2.2.0: {} + ts-interface-checker@0.1.13: {} tsconfck@2.1.2(typescript@5.2.2): @@ -8727,6 +10170,8 @@ snapshots: tslib@2.6.2: {} + tslib@2.8.1: {} + type-detect@4.0.8: {} type@2.7.2: {} @@ -8742,6 +10187,8 @@ snapshots: ufo@1.5.2: {} + ufo@1.5.4: {} + unified@11.0.5: dependencies: '@types/unist': 3.0.2 @@ -8836,6 +10283,313 @@ snapshots: uuid@9.0.0: {} + uuid@9.0.1: {} + + vega-canvas@1.2.7: {} + + vega-crossfilter@4.1.3: + dependencies: + d3-array: 3.2.4 + vega-dataflow: 5.7.7 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-dataflow@5.7.7: + dependencies: + vega-format: 1.1.3 + vega-loader: 4.5.3 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-embed@6.29.0(vega-lite@5.23.0(vega@5.31.0))(vega@5.31.0): + dependencies: + fast-json-patch: 3.1.1 + json-stringify-pretty-compact: 4.0.0 + semver: 7.7.1 + tslib: 2.8.1 + vega: 5.31.0 + vega-interpreter: 1.1.0 + vega-lite: 5.23.0(vega@5.31.0) + vega-schema-url-parser: 2.2.0 + vega-themes: 2.15.0(vega-lite@5.23.0(vega@5.31.0))(vega@5.31.0) + vega-tooltip: 0.35.2 + + vega-encode@4.10.2: + dependencies: + d3-array: 3.2.4 + d3-interpolate: 3.0.1 + vega-dataflow: 5.7.7 + vega-scale: 7.4.2 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-event-selector@3.0.1: {} + + vega-expression@5.1.2: + dependencies: + '@types/estree': 1.0.6 + vega-util: 1.17.3 + + vega-force@4.2.2: + dependencies: + d3-force: 3.0.0 + vega-dataflow: 5.7.7 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-format@1.1.3: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-time-format: 4.1.0 + vega-time: 2.1.3 + vega-util: 1.17.3 + + vega-functions@5.16.0: + dependencies: + d3-array: 3.2.4 + d3-color: 3.1.0 + d3-geo: 3.1.1 + vega-dataflow: 5.7.7 + vega-expression: 5.1.2 + vega-scale: 7.4.2 + vega-scenegraph: 4.13.1 + vega-selections: 5.5.0 + vega-statistics: 1.9.0 + vega-time: 2.1.3 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-geo@4.4.3: + dependencies: + d3-array: 3.2.4 + d3-color: 3.1.0 + d3-geo: 3.1.1 + vega-canvas: 1.2.7 + vega-dataflow: 5.7.7 + vega-projection: 1.6.2 + vega-statistics: 1.9.0 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-hierarchy@4.1.3: + dependencies: + d3-hierarchy: 3.1.2 + vega-dataflow: 5.7.7 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-interpreter@1.1.0: + dependencies: + vega-util: 1.17.3 + + vega-label@1.3.1: + dependencies: + vega-canvas: 1.2.7 + vega-dataflow: 5.7.7 + vega-scenegraph: 4.13.1 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-lite@5.23.0(vega@5.31.0): + dependencies: + json-stringify-pretty-compact: 4.0.0 + tslib: 2.8.1 + vega: 5.31.0 + vega-event-selector: 3.0.1 + vega-expression: 5.1.2 + vega-util: 1.17.3 + yargs: 17.7.2 + + vega-loader@4.5.3: + dependencies: + d3-dsv: 3.0.1 + node-fetch: 2.7.0 + topojson-client: 3.1.0 + vega-format: 1.1.3 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-parser@6.4.1: + dependencies: + vega-dataflow: 5.7.7 + vega-event-selector: 3.0.1 + vega-functions: 5.16.0 + vega-scale: 7.4.2 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-projection@1.6.2: + dependencies: + d3-geo: 3.1.1 + d3-geo-projection: 4.0.0 + vega-scale: 7.4.2 + + vega-regression@1.3.1: + dependencies: + d3-array: 3.2.4 + vega-dataflow: 5.7.7 + vega-statistics: 1.9.0 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-runtime@6.2.1: + dependencies: + vega-dataflow: 5.7.7 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-scale@7.4.2: + dependencies: + d3-array: 3.2.4 + d3-interpolate: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + vega-time: 2.1.3 + vega-util: 1.17.3 + + vega-scenegraph@4.13.1: + dependencies: + d3-path: 3.1.0 + d3-shape: 3.2.0 + vega-canvas: 1.2.7 + vega-loader: 4.5.3 + vega-scale: 7.4.2 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-schema-url-parser@2.2.0: {} + + vega-selections@5.5.0: + dependencies: + d3-array: 3.2.4 + vega-expression: 5.1.2 + vega-util: 1.17.3 + + vega-statistics@1.9.0: + dependencies: + d3-array: 3.2.4 + + vega-themes@2.15.0(vega-lite@5.23.0(vega@5.31.0))(vega@5.31.0): + dependencies: + vega: 5.31.0 + vega-lite: 5.23.0(vega@5.31.0) + + vega-time@2.1.3: + dependencies: + d3-array: 3.2.4 + d3-time: 3.1.0 + vega-util: 1.17.3 + + vega-tooltip@0.35.2: + dependencies: + vega-util: 1.17.3 + optionalDependencies: + '@rollup/rollup-linux-x64-gnu': 4.31.0 + + vega-transforms@4.12.1: + dependencies: + d3-array: 3.2.4 + vega-dataflow: 5.7.7 + vega-statistics: 1.9.0 + vega-time: 2.1.3 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-typings@1.4.0: + dependencies: + '@types/geojson': 7946.0.4 + vega-event-selector: 3.0.1 + vega-expression: 5.1.2 + vega-util: 1.17.3 + + vega-util@1.17.3: {} + + vega-view-transforms@4.6.1: + dependencies: + vega-dataflow: 5.7.7 + vega-scenegraph: 4.13.1 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-view@5.14.0: + dependencies: + d3-array: 3.2.4 + d3-timer: 3.0.1 + vega-dataflow: 5.7.7 + vega-format: 1.1.3 + vega-functions: 5.16.0 + vega-runtime: 6.2.1 + vega-scenegraph: 4.13.1 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-voronoi@4.2.4: + dependencies: + d3-delaunay: 6.0.4 + vega-dataflow: 5.7.7 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega-wordcloud@4.1.6: + dependencies: + vega-canvas: 1.2.7 + vega-dataflow: 5.7.7 + vega-scale: 7.4.2 + vega-statistics: 1.9.0 + vega-util: 1.17.3 + transitivePeerDependencies: + - encoding + + vega@5.31.0: + dependencies: + vega-crossfilter: 4.1.3 + vega-dataflow: 5.7.7 + vega-encode: 4.10.2 + vega-event-selector: 3.0.1 + vega-expression: 5.1.2 + vega-force: 4.2.2 + vega-format: 1.1.3 + vega-functions: 5.16.0 + vega-geo: 4.4.3 + vega-hierarchy: 4.1.3 + vega-label: 1.3.1 + vega-loader: 4.5.3 + vega-parser: 6.4.1 + vega-projection: 1.6.2 + vega-regression: 1.3.1 + vega-runtime: 6.2.1 + vega-scale: 7.4.2 + vega-scenegraph: 4.13.1 + vega-statistics: 1.9.0 + vega-time: 2.1.3 + vega-transforms: 4.12.1 + vega-typings: 1.4.0 + vega-util: 1.17.3 + vega-view: 5.14.0 + vega-view-transforms: 4.6.1 + vega-voronoi: 4.2.4 + vega-wordcloud: 4.1.6 + transitivePeerDependencies: + - encoding + vfile-location@5.0.2: dependencies: '@types/unist': 3.0.2 @@ -8896,7 +10650,7 @@ snapshots: vite@5.4.14(@types/node@20.5.7): dependencies: esbuild: 0.21.5 - postcss: 8.4.49 + postcss: 8.5.1 rollup: 4.31.0 optionalDependencies: '@types/node': 20.5.7 @@ -8942,6 +10696,23 @@ snapshots: void-elements@3.1.0: {} + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-textdocument@1.0.12: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-uri@3.0.8: {} + vt-pbf@3.1.3: dependencies: '@mapbox/point-geometry': 0.1.0 @@ -8960,6 +10731,8 @@ snapshots: dependencies: get-canvas-context: 1.0.2 + webidl-conversions@3.0.1: {} + webidl-conversions@7.0.0: {} whatwg-encoding@2.0.0: @@ -8973,6 +10746,11 @@ snapshots: tr46: 4.1.1 webidl-conversions: 7.0.0 + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + which-boxed-primitive@1.0.2: dependencies: is-bigint: 1.0.4 @@ -9033,10 +10811,24 @@ snapshots: xtend@4.0.2: {} + y18n@5.0.8: {} + yallist@3.1.1: {} yaml@2.4.1: {} + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + yocto-queue@1.0.0: {} zod@3.24.1: {} diff --git a/frontend/public/favicon.svg b/frontend/public/favicon.svg index 4da75b87bd..0ac341ad21 100644 --- a/frontend/public/favicon.svg +++ b/frontend/public/favicon.svg @@ -1,25 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index ba4b1467c4..3e3b56584e 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,9 +1,14 @@ -import { useEffect } from 'react'; +import { useContext, useEffect } from 'react'; import { RouterProvider } from 'react-router-dom'; import { useRecoilValue } from 'recoil'; import { router } from 'router'; -import { useAuth, useChatSession, useConfig } from '@chainlit/react-client'; +import { + ChainlitContext, + useAuth, + useChatSession, + useConfig +} from '@chainlit/react-client'; import ChatSettingsModal from './components/ChatSettings'; import { ThemeProvider } from './components/ThemeProvider'; @@ -25,8 +30,9 @@ declare global { function App() { const { config } = useConfig(); - const { isAuthenticated, data, isReady } = useAuth(); + const apiClient = useContext(ChainlitContext); const userEnv = useRecoilValue(userEnvState); + const { isAuthenticated, data, isReady, setUserFromAPI } = useAuth(); const { connect, chatProfile, setChatProfile } = useChatSession(); const configLoaded = !!config; @@ -37,6 +43,17 @@ function App() { : true : false; + useEffect(() => { + const searchParams = new URLSearchParams(location.search); + const token = + searchParams.get('access_token') || + localStorage.getItem('chainlit_token_iframe'); + apiClient + .jwtAuth(token) + .then((res) => setUserFromAPI()) + .catch((err) => console.log(err)); + }, []); + useEffect(() => { if (!isAuthenticated || !isReady || !chatProfileOk) { return; diff --git a/frontend/src/AppWrapper.tsx b/frontend/src/AppWrapper.tsx index 76509c4a1e..8622b72c62 100644 --- a/frontend/src/AppWrapper.tsx +++ b/frontend/src/AppWrapper.tsx @@ -10,6 +10,7 @@ import { useConfig } from '@chainlit/react-client'; + export default function AppWrapper() { const [translationLoaded, setTranslationLoaded] = useState(false); const { isAuthenticated, isReady } = useAuth(); @@ -17,20 +18,23 @@ export default function AppWrapper() { const { i18n } = useTranslation(); const { windowMessage } = useChatInteract(); - function handleChangeLanguage(languageBundle: any): void { - i18n.addResourceBundle(languageInUse, 'translation', languageBundle); - i18n.changeLanguage(languageInUse); + async function loadTranslation(language: string) { + try { + const translation = await import(`../../translations/${languageInUse}.json`); + i18n.addResourceBundle(language, 'translation', translation); + i18n.changeLanguage(language); + setTranslationLoaded(true) + } catch (error) { + console.error( + `Could not load translation for language: ${language}`, + error + ); + } } - const { data: translations } = useApi( - `/project/translations?language=${languageInUse}` - ); - useEffect(() => { - if (!translations) return; - handleChangeLanguage(translations.translation); - setTranslationLoaded(true); - }, [translations]); + loadTranslation(languageInUse); + }, []); useEffect(() => { const handleWindowMessage = (event: MessageEvent) => { diff --git a/frontend/src/assets/evoya_light.svg b/frontend/src/assets/evoya_light.svg new file mode 100644 index 0000000000..2fefd8115a --- /dev/null +++ b/frontend/src/assets/evoya_light.svg @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/frontend/src/components/Alert.tsx b/frontend/src/components/Alert.tsx index 8eb6e2d2d8..411de1f3c2 100644 --- a/frontend/src/components/Alert.tsx +++ b/frontend/src/components/Alert.tsx @@ -86,7 +86,7 @@ export const Alert: React.FC = ({ className )} > -
+
{icons[variant]}

{children}

diff --git a/frontend/src/components/CodeSnippet.tsx b/frontend/src/components/CodeSnippet.tsx index 4bb900173a..8cd9273711 100644 --- a/frontend/src/components/CodeSnippet.tsx +++ b/frontend/src/components/CodeSnippet.tsx @@ -26,7 +26,7 @@ const HighlightedCode = ({ language, children }: CodeSnippetProps) => { }, []); return ( -
+    
        {
   const [copied, setCopied] = useState(false);
   const { t } = useTranslation();
 
+  // Function to extract the image URL from the content
+  const extractImageUrl = (text: string): string | null => {
+    const regex = /!\[.*?\]\((https?:\/\/[^\s)]+)\)/;
+    const match = text.match(regex);
+    if (match) {
+      const url = match[1];
+      return url.includes('?type=image') ? url : null;
+    }
+    return null;
+  };
+
+  // Memoized image URL extraction
+  const imageUrl = useMemo(() => extractImageUrl(content), [content]);
+
   const copyToClipboard = async () => {
     try {
-      const textToCopy =
-        typeof content === 'object'
-          ? JSON.stringify(content, null, 2)
-          : String(content);
-
-      await navigator.clipboard.writeText(textToCopy);
+      await navigator.clipboard.writeText(content);
       setCopied(true);
 
       // Reset copied state after 2 seconds
-      setTimeout(() => {
-        setCopied(false);
-      }, 2000);
+      setTimeout(() => setCopied(false), 2000);
     } catch (err) {
       toast.error('Failed to copy: ' + String(err));
     }
   };
 
+  const handleDownload = () => {
+    if (!imageUrl) {
+      toast.error('No file URL found');
+      return;
+    }
+    const a = document.createElement('a');
+    a.href = imageUrl;
+    a.download = 'downloaded-image';
+    document.body.appendChild(a);
+    a.click();
+    document.body.removeChild(a);
+  };
+
   return (
     
-      
-        
-          
-        
-        
-          

- {copied - ? t('chat.messages.actions.copy.success') - : t('chat.messages.actions.copy.button')} -

-
-
+
+ + + + + +

+ {copied + ? t('chat.messages.actions.copy.success') + : t('chat.messages.actions.copy.button')} +

+
+
+ + {imageUrl && ( + + + + + +

{t('chat.messages.actions.download.button')}

+
+
+ )} +
); }; diff --git a/frontend/src/components/Elements/Audio.tsx b/frontend/src/components/Elements/Audio.tsx index 8e06e6d41c..b2b49b60de 100644 --- a/frontend/src/components/Elements/Audio.tsx +++ b/frontend/src/components/Elements/Audio.tsx @@ -1,16 +1,47 @@ import { cn } from '@/lib/utils'; +import { useEffect, useState } from 'react'; import { IAudioElement } from '@chainlit/react-client'; const AudioElement = ({ element }: { element: IAudioElement }) => { - if (!element.url) { - return null; - } + const [audioSrc, setAudioSrc] = useState(null); + + useEffect(() => { + if (!element.url) return; + + const fetchAudio = async () => { + const token = localStorage.getItem('chainlit_token'); + const headers: Record = { + ...(token ? { Authorization: `Bearer ${token}` } : {}) + }; + try { + const res = await fetch(element.url, { + headers, + credentials: 'include', + mode: 'cors' + }); + + if (!res.ok) throw new Error('Failed to fetch audio'); + + const blob = await res.blob(); + const url = URL.createObjectURL(blob); + setAudioSrc(url); + + return () => URL.revokeObjectURL(url); + } catch (err) { + console.error(err); + } + }; + + fetchAudio(); + }, [element.url]); + + if (!audioSrc) return null; return (

{element.name}

-
); }; diff --git a/frontend/src/components/FilePickerDialog.tsx b/frontend/src/components/FilePickerDialog.tsx new file mode 100644 index 0000000000..62a0b18482 --- /dev/null +++ b/frontend/src/components/FilePickerDialog.tsx @@ -0,0 +1,55 @@ +import { + Dialog, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, +} from '@/components/ui/dialog'; +import { Translator } from '@/components/i18n'; +import { Button } from './ui/button'; +import FilePicker from '@evoya/file-picker/src/components/FilePicker'; +import { EvoyaFile } from '@evoya/file-picker/src/types'; +import { FilePickerContext } from '@evoya/file-picker/src/context/file-context'; + +interface Props { + open: boolean; + setOpen: (val: boolean) => void; + selectFile: (val: EvoyaFile) => void +} + +const FilePickerDialog = ({ open, setOpen, selectFile }: Props): JSX.Element => { + return ( + + + + + + + +
+ + selectFile(item)} + singleMode + /> + +
+ + + +
+
+ ); +}; + +export { FilePickerDialog }; diff --git a/frontend/src/components/LeftSidebar/Search.tsx b/frontend/src/components/LeftSidebar/Search.tsx index 4e1ef30790..a223461703 100644 --- a/frontend/src/components/LeftSidebar/Search.tsx +++ b/frontend/src/components/LeftSidebar/Search.tsx @@ -38,25 +38,6 @@ export default function SearchChats() { const apiClient = useContext(ChainlitContext); - // Debounced search function - const debouncedSearch = useMemo( - () => - _.debounce(async (query: string) => { - setLoading(true); - try { - const { data } = await apiClient.listThreads( - { first: 20, cursor: undefined }, - { search: query || undefined } - ); - setThreads(data || []); - } catch (error) { - toast.error('Error fetching threads: ' + error); - } finally { - setLoading(false); - } - }, 300), - [apiClient] - ); // Group threads by month and year const groupedThreads = useMemo(() => { @@ -80,12 +61,6 @@ export default function SearchChats() { return () => document.removeEventListener('keydown', down); }, []); - useEffect(() => { - debouncedSearch(searchQuery); - return () => { - debouncedSearch.cancel(); - }; - }, [searchQuery, debouncedSearch]); return ( <> diff --git a/frontend/src/components/Markdown.tsx b/frontend/src/components/Markdown.tsx index aa72ef6b51..124822826c 100644 --- a/frontend/src/components/Markdown.tsx +++ b/frontend/src/components/Markdown.tsx @@ -1,8 +1,9 @@ import { cn } from '@/lib/utils'; import { omit } from 'lodash'; -import { useContext, useMemo } from 'react'; +import { isValidElement, useContext, useMemo } from 'react'; import ReactMarkdown from 'react-markdown'; import { PluggableList } from 'react-markdown/lib'; +import { VegaLite } from 'react-vega'; import rehypeKatex from 'rehype-katex'; import rehypeRaw from 'rehype-raw'; import remarkDirective from 'remark-directive'; @@ -10,6 +11,7 @@ import remarkGfm from 'remark-gfm'; import remarkMath from 'remark-math'; import { visit } from 'unist-util-visit'; +import ResponseTextItem from '@chainlit/copilot/src/evoya/privacyShield/ResponseTextItem'; import { ChainlitContext, type IMessageElement } from '@chainlit/react-client'; import { AspectRatio } from '@/components/ui/aspect-ratio'; @@ -28,6 +30,8 @@ import BlinkingCursor from './BlinkingCursor'; import CodeSnippet from './CodeSnippet'; import { ElementRef } from './Elements/ElementRef'; import { MarkdownAlert, alertComponents } from './MarkdownAlert'; +import { MermaidDiagram } from './Mermaid'; +import Step from './chat/Messages/Message/Step'; interface Props { allowHtml?: boolean; @@ -83,6 +87,26 @@ const cursorPlugin = () => { }; }; +const fixDirectiveColonPlugin = () => { + return (tree: any) => { + visit(tree, (node: any, index: number, parent: any) => { + if ( + (node.type === 'textDirective' || + node.type === 'leafDirective' || + node.type === 'containerDirective') && + !node.data?.hName && + /^[a-zA-Z0-9_-]+$/.test(node.name) + ) { + const directiveText = `:${node.name}`; + parent.children.splice(index, 1, { + type: 'text', + value: directiveText + }); + } + }); + }; +}; + const Markdown = ({ allowHtml, latex, @@ -90,6 +114,7 @@ const Markdown = ({ className, children }: Props) => { + const rawContent = children; const apiClient = useContext(ChainlitContext); const rehypePlugins = useMemo(() => { @@ -98,7 +123,10 @@ const Markdown = ({ rehypePlugins = [rehypeRaw as any, ...rehypePlugins]; } if (latex) { - rehypePlugins = [rehypeKatex as any, ...rehypePlugins]; + rehypePlugins = [ + [rehypeKatex as any, { output: 'mathml' }], + ...rehypePlugins + ]; } return rehypePlugins; }, [allowHtml, latex]); @@ -108,6 +136,7 @@ const Markdown = ({ cursorPlugin, remarkGfm as any, remarkDirective as any, + fixDirectiveColonPlugin, MarkdownAlert ]; @@ -123,7 +152,17 @@ const Markdown = ({ remarkPlugins={remarkPlugins} rehypePlugins={rehypePlugins} components={{ - ...alertComponents, // add alert components + ...alertComponents, + span({ children, ...props }) { + if (props.node?.properties.dataPrivacyComponent) { + return ( + + ); + } + return {children}; + }, code(props) { return ( + +
+ ); + } + } + + if (className?.includes('-mermaid')) { + return {rawContent}; + } + } + } catch (e) { + console.error('Render error:', e); + return ; + } + return ; }, a({ children, ...props }) { @@ -154,14 +222,14 @@ const Markdown = ({ }, img: (image: any) => { return ( -
+
; }, strong(props) { - return ; + // Check if the strong text contains an agent mention (starts with @) + const text = typeof props.children === 'string' ? props.children : ''; + const isAgentMention = text.trim().startsWith('@'); + + return ( + + ); }, hr() { return ; @@ -209,7 +286,7 @@ const Markdown = ({ return (

); }, @@ -217,7 +294,7 @@ const Markdown = ({ return (

); }, @@ -225,7 +302,7 @@ const Markdown = ({ return (

); }, @@ -233,17 +310,30 @@ const Markdown = ({ return (

); }, p(props) { + const thinkEndIndex = rawContent.indexOf(''); + const isBeforeThink = + typeof props.children == 'string' && + thinkEndIndex !== -1 && + rawContent.indexOf(props.children) < thinkEndIndex; return (
+ > + {props.children} +
); }, table({ children, ...props }) { @@ -253,6 +343,9 @@ const Markdown = ({ ); }, + li({ children, ...props }) { + return
  • {children}
  • + }, thead({ children, ...props }) { return {children}; }, diff --git a/frontend/src/components/Mermaid.tsx b/frontend/src/components/Mermaid.tsx new file mode 100644 index 0000000000..15be807983 --- /dev/null +++ b/frontend/src/components/Mermaid.tsx @@ -0,0 +1,136 @@ +import { useCallback, useEffect, useState, useMemo, ReactElement } from "react"; +import mermaid, { RenderResult } from "mermaid"; +import { Card } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip"; +import { X, ExternalLink, FileText } from "lucide-react"; +import { deflate } from "pako"; +import { fromUint8Array } from "js-base64"; +import { MouseEvent } from "react"; +import CopyButton from "./CopyButton"; +import { LoaderCircle } from "lucide-react" + +export interface MermaidDiagramProps { + children: string; + id?: string; + testId?: string; + className?: string; + onClick?: (event: MouseEvent) => void; + onError?: (error: any) => void; +} + +const MermaidDiagram = ({ children, id, testId, className, onClick }: MermaidDiagramProps): ReactElement => { + const [showSource, setShowSource] = useState(false); + const [element, setElement] = useState(null); + const [renderResult, setRenderResult] = useState(); + + const containerId = `${id || "d" + Date.now()}-mermaid`; + const diagramText = children; + + useEffect(() => { + mermaid.initialize({ startOnLoad: true, logLevel: 5 }); + }, []); + + const updateDiagramRef = useCallback((elem: HTMLDivElement) => { + if (!elem) return; + setElement(elem); + }, []); + + useEffect(() => { + if (showSource || !element || !renderResult?.svg) return; + element.innerHTML = renderResult.svg; + renderResult.bindFunctions?.(element); + }, [element, renderResult, showSource]); + + useEffect(() => { + if (!diagramText) return; + (async () => { + try { + const isValid = await mermaid.parse(diagramText, { suppressErrors: true }); + if (!isValid) return setRenderResult(undefined); + const rr = await mermaid.render(`${containerId}-svg`, diagramText); + setRenderResult(rr); + } catch { } + })(); + }, [diagramText]); + + const mermaidUrl = useMemo(() => { + try { + const formatJSON = (data: unknown): string => JSON.stringify(data, undefined, 2); + const serialize = (state: string): string => { + const data = new TextEncoder().encode(state); + const compressed = deflate(data, { level: 9 }); + return fromUint8Array(compressed, true); + } + const mermaidState: any = { + code: diagramText, + mermaid: formatJSON({ + theme: 'default' + }), + autoSync: false, + rough: false, + updateDiagram: true, + }; + + const json = JSON.stringify(mermaidState); + const serialized = serialize(json); + + return `https://mermaid.live/edit#pako:${serialized}`; + } catch (error) { + return ''; + } + }, [diagramText]); + + if (renderResult == undefined) { + return ( +
    + Generating mermaid diagram... +
    + ) + } + return ( +
    +
    + + + + + + Open in Mermaid Live + + + + + + Show graph source + + +
    +
    + {showSource && ( + +
    + + + + + + + Close + + +
    +
    {diagramText}
    +
    + )} +
    + ); +}; + +export { MermaidDiagram }; diff --git a/frontend/src/components/ReadOnlyThread.tsx b/frontend/src/components/ReadOnlyThread.tsx index e06d8da61c..b766a80597 100644 --- a/frontend/src/components/ReadOnlyThread.tsx +++ b/frontend/src/components/ReadOnlyThread.tsx @@ -177,6 +177,7 @@ const ReadOnlyThread = ({ id }: Props) => { return null; } + return (
    diff --git a/frontend/src/components/WaterMark.tsx b/frontend/src/components/WaterMark.tsx index effc2e56f5..9368263521 100644 --- a/frontend/src/components/WaterMark.tsx +++ b/frontend/src/components/WaterMark.tsx @@ -1,38 +1,67 @@ +import { useContext } from 'react'; import { Translator } from 'components/i18n'; -import 'assets/logo_dark.svg'; -import LogoDark from 'assets/logo_dark.svg?react'; -import 'assets/logo_light.svg'; -import LogoLight from 'assets/logo_light.svg?react'; +import 'assets/evoya_light.svg'; +import LogoDark from 'assets/evoya_light.svg?react'; +import LogoLight from 'assets/evoya_light.svg?react'; import { useTheme } from './ThemeProvider'; +import { WidgetContext } from '@chainlit/copilot/src/context'; export default function WaterMark() { const { variant } = useTheme(); + const { evoya } = useContext(WidgetContext); const Logo = variant === 'light' ? LogoLight : LogoDark; - return ( - -
    - -
    - -
    + <> + {!evoya?.hideWaterMark && ( + +
    + Powered by +
    + +
    + Evoya AI +
    +
    + )} + {evoya?.additionalInfo && ( +
    +

    + {evoya?.additionalInfo?.text ? ( + evoya?.additionalInfo?.text + ) : ( + + )} + {evoya?.additionalInfo?.link && ( + + {evoya.additionalInfo.linkText} + + )} +

    +
    + )} + ); } + diff --git a/frontend/src/components/chat/Footer.tsx b/frontend/src/components/chat/Footer.tsx index a6bdf1c28e..b68224d455 100644 --- a/frontend/src/components/chat/Footer.tsx +++ b/frontend/src/components/chat/Footer.tsx @@ -14,6 +14,7 @@ interface Props { setAutoScroll: (autoScroll: boolean) => void; autoScroll: boolean; showIfEmptyThread?: boolean; + submitProxy?: (text: string, submitFunction: (text: string) => void) => void; } export default function ChatFooter({ diff --git a/frontend/src/components/chat/MessageComposer/Attachment.tsx b/frontend/src/components/chat/MessageComposer/Attachment.tsx index 0a17d491a6..b01b40601d 100644 --- a/frontend/src/components/chat/MessageComposer/Attachment.tsx +++ b/frontend/src/components/chat/MessageComposer/Attachment.tsx @@ -8,14 +8,16 @@ import { TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; +import { Cloud, FolderOpen } from 'lucide-react'; interface AttachmentProps { name: string; mime: string; children?: React.ReactNode; + iconFlag?: React.ReactNode; } -const Attachment: React.FC = ({ name, mime, children }) => { +const Attachment: React.FC = ({ name, mime, children, iconFlag }) => { const extension = ( mime ? mime.split('/').pop() : 'txt' ) as DefaultExtensionType; @@ -24,13 +26,17 @@ const Attachment: React.FC = ({ name, mime, children }) => { -
    +
    {children} + {iconFlag} -
    - +
    + {mime === 'directory' && ( + + )} + {mime !== 'directory' && ()}
    - + {name} diff --git a/frontend/src/components/chat/MessageComposer/Attachments.tsx b/frontend/src/components/chat/MessageComposer/Attachments.tsx index ee7f32d386..e81f0bd891 100644 --- a/frontend/src/components/chat/MessageComposer/Attachments.tsx +++ b/frontend/src/components/chat/MessageComposer/Attachments.tsx @@ -1,4 +1,4 @@ -import { X } from 'lucide-react'; +import { X, Cloud } from 'lucide-react'; import React from 'react'; import { useRecoilValue } from 'recoil'; @@ -11,6 +11,7 @@ import { } from '@/components/ui/tooltip'; import { attachmentsState } from '@/state/chat'; +import { evoyaAttachmentsState } from '@/state/evoya'; import { Attachment } from './Attachment'; @@ -72,8 +73,9 @@ const CircularProgressButton = ({ }; const Attachments = () => { const attachments = useRecoilValue(attachmentsState); + const evoyaAttachments = useRecoilValue(evoyaAttachmentsState); - if (attachments.length === 0) return null; + if (attachments.length === 0 && evoyaAttachments.length === 0) return null; return (
    @@ -129,6 +131,49 @@ const Attachments = () => { ); })} + {evoyaAttachments.map((attachment) => { + const remove = + attachment.remove ? ( + + + +
    + +
    +
    + Remove attachment +
    +
    + ) : null; + + return ( + + + +
    + +
    +
    + Cloud Attachment +
    + + } + > + {remove} +
    + ); + })}
    ); }; diff --git a/frontend/src/components/chat/MessageComposer/CommandButton.tsx b/frontend/src/components/chat/MessageComposer/CommandButton.tsx index f74d60dc34..318b888d68 100644 --- a/frontend/src/components/chat/MessageComposer/CommandButton.tsx +++ b/frontend/src/components/chat/MessageComposer/CommandButton.tsx @@ -3,16 +3,20 @@ import { PopoverContent, PopoverTrigger } from '@radix-ui/react-popover'; +import { ChevronDown, StickyNote } from 'lucide-react'; +import { useEffect, useRef, useState } from 'react'; import { useRecoilValue } from 'recoil'; import { ICommand, commandsState } from '@chainlit/react-client'; -import Icon from '@/components/Icon'; +import { Translator } from '@/components/i18n'; import { ToolBox } from '@/components/icons/ToolBox'; import { Button } from '@/components/ui/button'; import { Command, + CommandEmpty, CommandGroup, + CommandInput, CommandItem, CommandList } from '@/components/ui/command'; @@ -26,64 +30,186 @@ import { interface Props { disabled?: boolean; onCommandSelect: (command: ICommand) => void; + selectedCommand: ICommand; } -export const CommandButton = ({ disabled = false, onCommandSelect }: Props) => { +export const CommandButton = ({ + disabled = false, + onCommandSelect, + selectedCommand +}: Props) => { const commands = useRecoilValue(commandsState); + const [open, setOpen] = useState(false); + const [searchResults, setSearchResults] = useState([]); + const [hoveredCommand, setHoveredCommand] = useState(null); + const [displayedCommand, setDisplayedCommand] = useState( + null + ); + const [searchTerm, setSearchTerm] = useState(''); + const [isMobile, setIsMobile] = useState(false); + + useEffect(() => { + const checkIfMobile = () => { + setIsMobile(window.innerWidth < 1024); + }; + + checkIfMobile(); + window.addEventListener('resize', checkIfMobile); + + return () => { + window.removeEventListener('resize', checkIfMobile); + }; + }, []); + + useEffect(() => { + setSearchResults(commands); + }, [commands]); + + useEffect(() => { + setDisplayedCommand( + hoveredCommand || selectedCommand || searchResults[0] || null + ); + }, [hoveredCommand, selectedCommand, searchResults]); + + const handleSearch = (value: string) => { + setSearchTerm(value); + if (!value.trim()) { + setSearchResults(commands); + return; + } + + const filtered = commands.filter( + (command) => + command.id.toLowerCase().includes(value.toLowerCase()) || + command.description?.toLowerCase().includes(value.toLowerCase()) || + command.prompt_content?.toLowerCase().includes(value.toLowerCase()) + ); + setSearchResults(filtered); + }; + + const handleMouseEnter = (command) => { + setTimeout(() => { + setHoveredCommand(command); + }, 200); + }; + + const inputRef = useRef(null); + const buttonRef = useRef(null); + + useEffect(() => { + const timer = setTimeout(() => { + if (inputRef.current) { + inputRef.current.focus(); + } + }, 100); + + return () => clearTimeout(timer); + }, [open]); if (!commands.length) return null; return ( - + { + setOpen(open); + setHoveredCommand(null); + setSearchResults(commands); + }} + > - -

    Commands

    + +
    - - - - {commands.map((command) => ( - onCommandSelect(command)} - className="command-item cursor-pointer flex items-center space-x-2 p-2" - > - -
    -
    {command.id}
    -
    - {command.description} +
    + +
    + +
    + + No results found. +
    + + {searchResults.map((command) => ( + { + onCommandSelect(command); + setOpen(false); + setTimeout(() => { + if (buttonRef.current) { + buttonRef.current.blur(); + } + }, 10); + }} + className="command-item cursor-pointer px-3 py-3 justify-between rounded-md" + onMouseEnter={() => handleMouseEnter(command)} + > +
    +
    {command.id}
    +
    + {command.description} +
    +
    +
    + +
    +
    + ))} +
    + {searchResults.length > 0 && !isMobile && ( +
    +
    +
    +

    + {displayedCommand?.prompt_content || + 'Select a command to view its content'} +

    +
    - - ))} - - - + )} +
    +
    +
    +
    ); diff --git a/frontend/src/components/chat/MessageComposer/Input.tsx b/frontend/src/components/chat/MessageComposer/Input.tsx index 3551cb13b5..e44766ecd8 100644 --- a/frontend/src/components/chat/MessageComposer/Input.tsx +++ b/frontend/src/components/chat/MessageComposer/Input.tsx @@ -1,4 +1,5 @@ import { cn } from '@/lib/utils'; +import { ChevronDown } from 'lucide-react'; import React, { forwardRef, useEffect, @@ -8,16 +9,20 @@ import React, { } from 'react'; import { useRecoilValue } from 'recoil'; -import { ICommand, commandsState } from '@chainlit/react-client'; +import { ICommand, agentState, commandsState } from '@chainlit/react-client'; -import Icon from '@/components/Icon'; +import { Translator } from '@/components/i18n'; import { Command, + CommandEmpty, CommandGroup, + CommandInput, CommandItem, CommandList } from '@/components/ui/command'; +import { useIsMobile } from '@/hooks/use-mobile'; + interface Props { id?: string; className?: string; @@ -28,10 +33,15 @@ interface Props { onChange: (value: string) => void; onPaste?: (event: any) => void; onEnter?: (event: React.KeyboardEvent) => void; + selectedAgents?: any[]; + setSelectedAgents?: (agents: any[]) => void; } export interface InputMethods { reset: () => void; + getFullContent: () => string; + setContent: (value: string) => void; + appendContent: (value: string) => void; } const escapeHtml = (unsafe: string) => { @@ -43,6 +53,12 @@ const escapeHtml = (unsafe: string) => { .replace(/'/g, '''); }; +const formatContent = (value: string) => { + return escapeHtml(value) + .replace(/\n/g, '
    ') + .replace(/\t/g, '    '); +}; + const Input = forwardRef( ( { @@ -54,19 +70,39 @@ const Input = forwardRef( setSelectedCommand, onChange, onEnter, - onPaste + onPaste, + selectedAgents: propSelectedAgents, + setSelectedAgents: propSetSelectedAgents }, ref ) => { const commands = useRecoilValue(commandsState); + const agents = useRecoilValue(agentState); const [isComposing, setIsComposing] = useState(false); const [showCommands, setShowCommands] = useState(false); + const [showAgents, setShowAgents] = useState(false); const [selectedIndex, setSelectedIndex] = useState(0); const [commandInput, setCommandInput] = useState(''); + const [agentInput, setAgentInput] = useState(''); + const [_localSelectedAgents, _setLocalSelectedAgents] = useState([]); + + // Use props if provided, otherwise use local state + const selectedAgents = + propSelectedAgents !== undefined + ? propSelectedAgents + : _localSelectedAgents; + const setSelectedAgents = + propSetSelectedAgents !== undefined + ? propSetSelectedAgents + : _setLocalSelectedAgents; + const contentEditableRef = useRef(null); const lastCommandSpanRef = useRef(null); + const lastAgentSpanRef = useRef(null); const mutationObserverRef = useRef(null); const isUpdatingRef = useRef(false); + const [isCommandExpanded, setIsCommandExpanded] = useState(false); + const isMobile = useIsMobile(); const getContentWithoutCommand = () => { if (!contentEditableRef.current) return ''; @@ -93,18 +129,69 @@ const Input = forwardRef( ); }; + const getFullContent = () => { + // Get base content + const baseContent = getContentWithoutCommand(); + + // Prepend agents to the message as part of the text with markdown-like formatting + if (selectedAgents && selectedAgents.length > 0) { + const agentMentions = selectedAgents + .map((agent) => `**@${agent.name}**`) + .join(' '); + return `${agentMentions}\n${baseContent}`.trim(); + } + + return baseContent; + }; + const reset = () => { setSelectedCommand(undefined); setSelectedIndex(0); setCommandInput(''); + setAgentInput(''); + setIsCommandExpanded(false); + setShowAgents(false); + setShowCommands(false); + setSelectedAgents([]); if (contentEditableRef.current) { contentEditableRef.current.innerHTML = ''; } onChange(''); }; + const placeCursorAtEnd = (element: HTMLDivElement) => { + const selection = window.getSelection(); + const range = document.createRange(); + + range.selectNodeContents(element); + range.collapse(false); + + selection?.removeAllRanges(); + selection?.addRange(range); + element.focus(); + }; + + const syncContent = (value: string, mode: 'replace' | 'append') => { + const content = contentEditableRef.current; + if (!content) return; + + if (mode === 'replace') { + reset(); + } + + const baseContent = + mode === 'append' ? getContentWithoutCommand() + value : value; + + content.innerHTML = formatContent(baseContent); + onChange(baseContent); + placeCursorAtEnd(content); + }; + useImperativeHandle(ref, () => ({ - reset + reset, + getFullContent, + setContent: (value: string) => syncContent(value, 'replace'), + appendContent: (value: string) => syncContent(value, 'append') })); // Set up mutation observer to detect command span removal @@ -128,9 +215,18 @@ const Input = forwardRef( (node as HTMLElement).classList?.contains('command-span') ); + // Check if the removed node was our agent span + const wasAgentSpanRemoved = Array.from(mutation.removedNodes).some( + (node) => (node as HTMLElement).classList?.contains('agent-span') + ); + if (wasCommandSpanRemoved && !mutation.addedNodes.length) { handleCommandSelect(undefined); } + + if (wasAgentSpanRemoved && !mutation.addedNodes.length) { + lastAgentSpanRef.current = null; + } } }); }); @@ -145,6 +241,33 @@ const Input = forwardRef( }; }, []); + // Monitor input changes to detect when expanded content is completely removed + useEffect(() => { + if (!selectedCommand || !isCommandExpanded) return; + + const content = contentEditableRef.current; + if (!content) return; + + const handleContentChange = () => { + if (isUpdatingRef.current) return; + + const currentText = content.textContent || ''; + + // Only reset if the content is completely empty or just whitespace + // This prevents interference with normal editing/backspacing + if (!currentText.trim()) { + setSelectedCommand(undefined); + setIsCommandExpanded(false); + } + }; + + content.addEventListener('input', handleContentChange); + + return () => { + content.removeEventListener('input', handleContentChange); + }; + }, [selectedCommand, isCommandExpanded]); + // Handle selectedCommand prop changes useEffect(() => { const content = contentEditableRef.current; @@ -157,126 +280,239 @@ const Input = forwardRef( const existingCommandSpan = content.querySelector('.command-span'); if (selectedCommand) { - // Create new command block - const newCommandBlock = document.createElement('div'); - newCommandBlock.className = - 'command-span font-bold inline-flex text-[#08f] items-center mr-1'; - newCommandBlock.contentEditable = 'false'; - newCommandBlock.innerHTML = `${selectedCommand.id}`; + if (isCommandExpanded) { + // When expanded, replace the command with editable text content + const promptContent = + selectedCommand.prompt_content || selectedCommand.id; + + // Remove any existing command span + if (existingCommandSpan) { + existingCommandSpan.remove(); + } - // Store reference to the command span - lastCommandSpanRef.current = newCommandBlock; + // Create a div to hold the formatted content + const contentDiv = document.createElement('div'); + contentDiv.style.display = 'inline'; + contentDiv.contentEditable = 'true'; - if (existingCommandSpan) { - existingCommandSpan.replaceWith(newCommandBlock); - } else { - // Add new command span at the start + // Convert newlines to
    tags and preserve other formatting + const formattedContent = formatContent(promptContent); + + contentDiv.innerHTML = formattedContent + ' '; + + // Insert the formatted content at the beginning if (content.firstChild) { - content.insertBefore(newCommandBlock, content.firstChild); + content.insertBefore(contentDiv, content.firstChild); } else { - content.appendChild(newCommandBlock); + content.appendChild(contentDiv); } - } - let textNode; + lastCommandSpanRef.current = null; // No reference needed for expanded state + + // For expanded state, set cursor after the inserted content + content.focus(); + + // Move cursor to end of content + const selection = window.getSelection(); + const range = document.createRange(); + range.selectNodeContents(content); + range.collapse(false); + + selection?.removeAllRanges(); + selection?.addRange(range); - // Create a text node after the command span if none exists - if (!newCommandBlock.nextSibling) { - textNode = document.createTextNode('\u200B'); - content.appendChild(textNode); // Zero-width space + onChange(getContentWithoutCommand()); + } else { + // When collapsed, show as command span with expand button + + const newCommandBlock = document.createElement('div'); + newCommandBlock.className = + 'command-span font-bold inline-flex text-[#08f] items-center mr-1'; + newCommandBlock.contentEditable = 'false'; + + const commandContent = ` +
    + + ${selectedCommand.id} +
    + `; + + newCommandBlock.innerHTML = commandContent; + + // Store reference to the command span + lastCommandSpanRef.current = newCommandBlock; + + // Add click event listener for the entire command area + const clickableArea = + newCommandBlock.querySelector('.command-clickable'); + if (clickableArea) { + clickableArea.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + setIsCommandExpanded(true); + }); + } + + if (existingCommandSpan) { + existingCommandSpan.replaceWith(newCommandBlock); + } else { + // Add new command span at the start + if (content.firstChild) { + content.insertBefore(newCommandBlock, content.firstChild); + } else { + content.appendChild(newCommandBlock); + } + } + + // Ensure there's a text node after the command block for cursor positioning + let textNode = newCommandBlock.nextSibling; + if (!textNode || textNode.nodeType !== Node.TEXT_NODE) { + textNode = document.createTextNode('\u200B'); // Zero-width space + content.appendChild(textNode); + } + + // Create and set the selection range + const selection = window.getSelection(); + selection?.removeAllRanges(); + const range = document.createRange(); + + // Set cursor position at the beginning of the text node + range.setStart(textNode, 0); + range.collapse(true); + + // Apply the selection + selection?.addRange(range); + + // Force focus with delay to ensure it happens after any button close events + content.focus(); + + // Double-focus technique - helps in some browsers/situations + setTimeout(() => { + // Make sure caret is visible + content.style.caretColor = 'black'; + + // Re-focus and set cursor position again + content.focus(); + + if (selection?.rangeCount && selection.rangeCount > 0) { + selection.removeAllRanges(); + selection.addRange(range); + } + + // Trigger onChange with content excluding command + onChange(getContentWithoutCommand()); + }, 10); + } + } else { + // Remove existing command span + if (existingCommandSpan) { + existingCommandSpan.remove(); } + lastCommandSpanRef.current = null; - // Ensure cursor is placed after the command span - const selection = window.getSelection(); + // Ensure cursor is placed at start const range = document.createRange(); - - // Set cursor after the command span - range.setStartAfter(textNode || newCommandBlock); + range.setStart(content, 0); range.collapse(true); - // Apply the selection + const selection = window.getSelection(); selection?.removeAllRanges(); selection?.addRange(range); - // Force focus on the content editable content.focus(); - selection?.addRange(range); - - // Trigger onChange with content excluding command - onChange(getContentWithoutCommand()); - } else if (existingCommandSpan) { - // Remove existing command span - existingCommandSpan.remove(); - lastCommandSpanRef.current = null; onChange(getContentWithoutCommand()); } } finally { // Use setTimeout to ensure all DOM updates are complete setTimeout(() => { isUpdatingRef.current = false; - }, 0); + }, 20); } - }, [selectedCommand, onChange]); + }, [selectedCommand, onChange, isCommandExpanded]); const normalizedInput = commandInput.toLowerCase().slice(1); const filteredCommands = commands - .filter((command) => command.id.toLowerCase().includes(normalizedInput)) + ?.filter((command) => command.id.toLowerCase().includes(normalizedInput)) .sort((a, b) => { const indexA = a.id.toLowerCase().indexOf(normalizedInput); const indexB = b.id.toLowerCase().indexOf(normalizedInput); return indexA - indexB; }); + // Improved paste handler that works across browsers useEffect(() => { const textarea = contentEditableRef.current; if (!textarea || !onPaste) return; - const _onPaste = (event: ClipboardEvent) => { + const handlePaste = (event: ClipboardEvent) => { + // Prevent the default paste behavior event.preventDefault(); + // Get plain text from clipboard const textData = event.clipboardData?.getData('text/plain'); - if (textData) { - const escapedText = escapeHtml(textData); - const textWithNewLines = escapedText.replace(/\n/g, '
    '); - - const selection = window.getSelection(); - if (selection?.rangeCount) { - const range = selection.getRangeAt(0); - range.deleteContents(); - - // Insert the HTML content - const tempDiv = document.createElement('div'); - tempDiv.innerHTML = textWithNewLines; - const fragment = document.createDocumentFragment(); - while (tempDiv.firstChild) { - fragment.appendChild(tempDiv.firstChild); - } - range.insertNode(fragment); + // Process the text - convert newlines to
    tags and escape HTML + const escapedText = escapeHtml(textData || ''); + const textWithNewLines = escapedText.replace(/\n/g, '
    '); + + // Handle insertion into the DOM + // Use execCommand for better cross-browser compatibility + if (document.queryCommandSupported('insertHTML')) { + document.execCommand('insertHTML', false, textWithNewLines); + } else { + // Fallback method for browsers that don't support execCommand + insertTextAtCursor(textWithNewLines); + } - // Move cursor to end of pasted content - range.collapse(false); - selection.removeAllRanges(); - selection.addRange(range); + // Ensure the textarea has focus + textarea.focus(); - // Force focus back to the content editable - textarea.focus(); - textarea.scrollTop = textarea.scrollHeight; - } + // Call the onPaste callback + onPaste(event); - // Trigger input event to update state + // Trigger input event to update state + setTimeout(() => { const inputEvent = new Event('input', { bubbles: true }); textarea.dispatchEvent(inputEvent); + }, 0); + }; + + // Helper function to insert text at cursor position + const insertTextAtCursor = (html: string) => { + const selection = window.getSelection(); + if (!selection?.rangeCount) return; + + const range = selection.getRangeAt(0); + range.deleteContents(); + + // Create a fragment with our HTML + const fragment = document.createDocumentFragment(); + const tempDiv = document.createElement('div'); + tempDiv.innerHTML = html; + + // Move nodes from temp div to fragment + while (tempDiv.firstChild) { + fragment.appendChild(tempDiv.firstChild); } - onPaste(event); + // Insert the fragment + range.insertNode(fragment); + + // Move cursor to end of inserted content + range.collapse(false); + selection?.removeAllRanges(); + selection?.addRange(range); }; - textarea.addEventListener('paste', _onPaste); + textarea.addEventListener('paste', handlePaste); return () => { - textarea.removeEventListener('paste', _onPaste); + textarea.removeEventListener('paste', handlePaste); }; }, [onPaste]); @@ -293,9 +529,18 @@ const Input = forwardRef( if (lastWord.startsWith('/')) { setShowCommands(true); setCommandInput(lastWord); + setShowAgents(false); + setAgentInput(''); + } else if (lastWord.startsWith('@')) { + setShowAgents(true); + setAgentInput(lastWord); + setShowCommands(false); + setCommandInput(''); } else { setShowCommands(false); + setShowAgents(false); setCommandInput(''); + setAgentInput(''); } // If there's no real content, remove the
    @@ -304,15 +549,61 @@ const Input = forwardRef( } }; + const normalizedAgentInput = agentInput.toLowerCase().slice(1); + const filteredAgents = + agents?.agents?.length > 0 && + agents?.agents + .filter((agent) => + agent.name.toLowerCase().includes(normalizedAgentInput) + ) + .sort((a, b) => { + const indexA = a.name.toLowerCase().indexOf(normalizedAgentInput); + const indexB = b.name.toLowerCase().indexOf(normalizedAgentInput); + return indexA - indexB; + }); + const handleKeyDown = (e: React.KeyboardEvent) => { - if (!showCommands) { + if (!showCommands && !showAgents) { if (e.key === 'Enter' && !e.shiftKey && onEnter && !isComposing) { + // Check if on mobile device + if (isMobile) { + // On mobile, only send if there's a special modifier key pressed + // This allows normal Enter presses to create new lines + if (e.ctrlKey) { + e.preventDefault(); + onEnter(e); + } + // Otherwise let the default behavior happen (create new line) + } else { + // On desktop, maintain current behavior + e.preventDefault(); + onEnter(e); + } + } + return; + } + + // Handle agent navigation + if (showAgents) { + if (e.key === 'ArrowDown') { e.preventDefault(); - onEnter(e); + setSelectedIndex((prev) => + prev < filteredAgents.length - 1 ? prev + 1 : prev + ); + } else if (e.key === 'ArrowUp') { + e.preventDefault(); + setSelectedIndex((prev) => (prev > 0 ? prev - 1 : prev)); + } else if (e.key === 'Enter' && filteredAgents.length > 0) { + e.preventDefault(); + const selectedAgent = filteredAgents[selectedIndex]; + handleAgentSelect(selectedAgent); + } else if (e.key === 'Escape') { + setShowAgents(false); } return; } + // Handle command navigation if (e.key === 'ArrowDown') { e.preventDefault(); setSelectedIndex((prev) => @@ -332,9 +623,15 @@ const Input = forwardRef( const handleCommandSelect = (command?: ICommand) => { setShowCommands(false); + setIsCommandExpanded(false); // Reset expansion state when selecting a new command // Set a small timeout to ensure state updates are processed setTimeout(() => { + // If there's an existing command and we're selecting a new one, clear the content first + if (selectedCommand && command && contentEditableRef.current) { + contentEditableRef.current.innerHTML = ''; + } + setSelectedCommand(command); // Clean up the command input from contentEditable @@ -349,8 +646,91 @@ const Input = forwardRef( }, 0); }; + const handleAgentSelect = (agent: any) => { + setShowAgents(false); + setSelectedIndex(0); + + // Add agent to the list if not already present + setSelectedAgents((prev) => { + const agentExists = prev.some((a) => a.uuid === agent.uuid); + if (agentExists) return prev; + return [...prev, agent]; + }); + + // Clean up the agent input text from contentEditable + if (contentEditableRef.current) { + const content = contentEditableRef.current; + const textContent = content.textContent || ''; + const cleanedContent = textContent.replace(agentInput, '').trimStart(); + content.textContent = cleanedContent; + + // Set cursor at the end of the content + const selection = window.getSelection(); + const range = document.createRange(); + range.selectNodeContents(content); + range.collapse(false); // false means collapse to the end + selection?.removeAllRanges(); + selection?.addRange(range); + + content.focus(); + onChange(cleanedContent); + } + + setAgentInput(''); + }; + + const handleRemoveAgent = (agentId: string) => { + setSelectedAgents((prev) => prev.filter((a) => a.uuid !== agentId)); + if (contentEditableRef.current) { + contentEditableRef.current.focus(); + } + }; + + const handleMouseEnter = (index: number) => { + // Small delay before changing the displayed command + setTimeout(() => { + setSelectedIndex(index); + }, 100); + }; + return (
    + {selectedAgents.length > 0 && ( +
    + {selectedAgents.map((agent) => { + if (agent?.name) { + return ( +
    + + @{agent.name} + + +
    + ); + } + })} +
    + )}
    ( onCompositionStart={() => setIsComposing(true)} onCompositionEnd={() => setIsComposing(false)} /> - + {/* Add a send button for mobile users + {isMobile && ( + + )} */} {showCommands && filteredCommands.length ? ( -
    - - - - {filteredCommands.map((command, index) => ( - handleCommandSelect(command)} - className={cn( - 'cursor-pointer command-item flex items-center space-x-2 p-2', - index === selectedIndex ? 'bg-accent' : '' - )} - > - -
    -
    {command.id}
    -
    - {command.description} +
    +
    + +
    + +
    + + No results found. +
    + + {filteredCommands.map((command, index) => ( + { + handleCommandSelect(command); + setShowCommands(false); + }} + onMouseEnter={() => handleMouseEnter(index)} + className={cn( + 'command-item !bg-transparent cursor-pointer px-3 py-3 justify-between rounded-md', + index === selectedIndex ? '!bg-accent' : '' + )} + > +
    +
    + {command.id} +
    +
    + {command.description} +
    +
    +
    + +
    +
    + ))} +
    + {filteredCommands.length > 0 && !isMobile && ( +
    +
    +
    +

    + {filteredCommands[selectedIndex]?.description || + 'Select a command to view its content'} +

    +
    +
    +
    + )} +
    +
    +
    +
    +
    + ) : null} + {showAgents && filteredAgents.length ? ( +
    +
    + +
    + +
    + + No agents found. +
    + + {filteredAgents.map((agent, index) => ( + { + handleAgentSelect(agent); + setShowAgents(false); + }} + onMouseEnter={() => handleMouseEnter(index)} + className={cn( + 'command-item !bg-transparent cursor-pointer px-3 py-3 justify-between rounded-md', + index === selectedIndex ? '!bg-accent' : '' + )} + > +
    +
    + {agent.name} +
    +
    +
    + +
    +
    + ))} +
    + {filteredAgents.length > 0 && !isMobile && ( +
    +
    +
    +

    + {filteredAgents[selectedIndex]?.description || ( + + )} +

    +
    - - ))} - - - + )} +
    +
    +
    +
    ) : null}
    diff --git a/frontend/src/components/chat/MessageComposer/Projects.tsx b/frontend/src/components/chat/MessageComposer/Projects.tsx new file mode 100644 index 0000000000..ab4ee26661 --- /dev/null +++ b/frontend/src/components/chat/MessageComposer/Projects.tsx @@ -0,0 +1,324 @@ +import { cn } from '@/lib/utils'; +import { Check, FolderOpen, Search } from 'lucide-react'; +import { + useCallback, + useContext, + useEffect, + useMemo, + useRef, + useState +} from 'react'; + +import { WidgetContext } from '@chainlit/copilot/src/context'; + +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { + Popover, + PopoverContent, + PopoverTrigger +} from '@/components/ui/popover'; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger +} from '@/components/ui/tooltip'; +import Translator from '@/components/i18n/Translator'; + +type ProjectId = string | number; + +interface DashboardBridgeProject { + id?: ProjectId; + uuid?: string; + project_uuid?: string; + projectUuid?: string; + name?: string; + title?: string; + project__name?: string; + description?: string; + slug?: string; + [key: string]: unknown; +} + +interface ProjectListItem { + id: string; + name: string; + description?: string; + raw: DashboardBridgeProject; +} + +interface DashboardProjectBridgeData { + projects?: DashboardBridgeProject[]; + selectedProjects?: DashboardBridgeProject[]; + filteredProjects?: DashboardBridgeProject[]; + projectSearch?: string; + getProjects?: () => DashboardBridgeProject[]; + getSelectedProjects?: () => DashboardBridgeProject[]; + getFilteredProjects?: () => DashboardBridgeProject[]; + getProjectSearch?: () => string; + setProjectSearch?: (query: string) => void; + isProjectSelected?: (projectUuid: string) => boolean; + toggleProject?: (project: DashboardBridgeProject) => void; + removeProject?: (projectUuid: string) => void; + syncProjectContext?: () => void; +} + +const projectEvents = [ + 'reload-chat-sidebar', + 'project-changed', + 'projects-changed', + 'project-context-changed', + 'project-picker-changed' +]; + +const getBridgeData = () => { + if (typeof window === 'undefined') return undefined; + const dashboardWindow = window as Window & { + dashboardDataForModal?: () => DashboardProjectBridgeData; + }; + return dashboardWindow.dashboardDataForModal?.(); +}; + +const getProjectId = (project: DashboardBridgeProject) => + project.uuid || project.project_uuid || project.projectUuid || project.id; + +const getProjectName = (project: DashboardBridgeProject) => + project.name || project.title || project.project__name || 'Untitled Project'; + +const mapProject = ( + project: DashboardBridgeProject +): ProjectListItem | null => { + const id = getProjectId(project); + if (id === undefined || id === null) return null; + + return { + id: String(id), + name: getProjectName(project), + description: project.description, + raw: project + }; +}; + +const truncateProjectName = (name: string, length = 34) => + name.length > length ? `${name.slice(0, length)}...` : name; + +const ProjectRow = ({ + project, + selected, + onClick +}: { + project: ProjectListItem; + selected: boolean; + onClick: () => void; +}) => ( + +); + +interface Props { + disabled?: boolean; +} + +export default function Projects({ disabled = false }: Props) { + const { evoya } = useContext(WidgetContext); + const [projects, setProjects] = useState([]); + const [bridgeFilteredProjects, setBridgeFilteredProjects] = useState< + ProjectListItem[] + >([]); + const [selectedProjects, setSelectedProjects] = useState( + [] + ); + const [isOpen, setIsOpen] = useState(false); + const [query, setQuery] = useState(''); + const searchInputRef = useRef(null); + + const syncFromBridge = useCallback(() => { + const data = getBridgeData(); + if (!data) { + setProjects([]); + setBridgeFilteredProjects([]); + setSelectedProjects([]); + return; + } + + const nextProjects = (data.getProjects?.() ?? data.projects ?? []) + .map(mapProject) + .filter((project): project is ProjectListItem => !!project); + const nextSelectedProjects = ( + data.getSelectedProjects?.() ?? + data.selectedProjects ?? + [] + ) + .map(mapProject) + .filter((project): project is ProjectListItem => !!project); + const nextFilteredProjects = ( + data.getFilteredProjects?.() ?? + data.filteredProjects ?? + [] + ) + .map(mapProject) + .filter((project): project is ProjectListItem => !!project); + + setProjects(nextProjects); + setSelectedProjects(nextSelectedProjects); + setBridgeFilteredProjects(nextFilteredProjects); + setQuery(data.getProjectSearch?.() ?? data.projectSearch ?? ''); + }, []); + + useEffect(() => { + if (evoya?.type !== 'dashboard') return; + + syncFromBridge(); + const handleProjectEvent = () => syncFromBridge(); + + projectEvents.forEach((eventName) => { + window.addEventListener(eventName, handleProjectEvent); + }); + + return () => { + projectEvents.forEach((eventName) => { + window.removeEventListener(eventName, handleProjectEvent); + }); + }; + }, [evoya?.type, syncFromBridge]); + + const normalizedQuery = query.trim().toLowerCase(); + const selectedProjectIds = useMemo( + () => new Set(selectedProjects.map((project) => project.id)), + [selectedProjects] + ); + + const visibleProjects = useMemo(() => { + const source = + bridgeFilteredProjects.length || !normalizedQuery + ? bridgeFilteredProjects.length + ? bridgeFilteredProjects + : projects + : projects; + + if (!normalizedQuery) return source; + + return source.filter( + (project) => + project.name.toLowerCase().includes(normalizedQuery) || + project.description?.toLowerCase().includes(normalizedQuery) + ); + }, [bridgeFilteredProjects, normalizedQuery, projects]); + + const syncAfterBridgeAction = () => { + window.setTimeout(syncFromBridge, 0); + }; + + const handleOpenChange = (open: boolean) => { + setIsOpen(open); + if (open) { + syncAfterBridgeAction(); + } + }; + + const handleSearch = (value: string) => { + const data = getBridgeData(); + setQuery(value); + data?.setProjectSearch?.(value); + syncAfterBridgeAction(); + }; + + const handleToggleProject = (project: ProjectListItem) => { + const data = getBridgeData(); + data?.toggleProject?.(project.raw); + data?.syncProjectContext?.(); + syncAfterBridgeAction(); + setIsOpen(false); + }; + + if ( + evoya?.type !== 'dashboard' + ) { + return null; + } + + return ( + + + + + + + + + + + + + + + { + event.preventDefault(); + searchInputRef.current?.focus(); + }} + > +
    + + handleSearch(event.target.value)} + placeholder="Search projects..." + className="h-10 rounded-xl border-slate-200 bg-white pl-9 pr-3 text-base shadow-none focus-visible:ring-1 focus-visible:ring-primary/25 focus-visible:ring-offset-0 md:text-base" + autoFocus + /> +
    + +
    +
    + {visibleProjects.map((project) => ( + handleToggleProject(project)} + /> + ))} + {!visibleProjects.length ? ( +

    + +

    + ) : null} +
    +
    +
    +
    + ); +} diff --git a/frontend/src/components/chat/MessageComposer/SubmitButton.tsx b/frontend/src/components/chat/MessageComposer/SubmitButton.tsx index fb5a7da7aa..bd1d924e5d 100644 --- a/frontend/src/components/chat/MessageComposer/SubmitButton.tsx +++ b/frontend/src/components/chat/MessageComposer/SubmitButton.tsx @@ -1,10 +1,13 @@ +import { Send } from 'lucide-react'; +import { useContext } from 'react'; + +import { WidgetContext } from '@chainlit/copilot/src/context'; import { useChatData, useChatInteract, useChatMessages } from '@chainlit/react-client'; -import { Send } from '@/components/icons/Send'; import { Stop } from '@/components/icons/Stop'; import { Button } from '@/components/ui/button'; import { @@ -15,31 +18,52 @@ import { } from '@/components/ui/tooltip'; import { Translator } from 'components/i18n'; +import VoiceButton from './VoiceButton'; + interface SubmitButtonProps { disabled?: boolean; + value?: string; onSubmit: () => void; } export default function SubmitButton({ disabled, - onSubmit + onSubmit, + value }: SubmitButtonProps) { + const { evoya } = useContext(WidgetContext); const { loading } = useChatData(); const { firstInteraction } = useChatMessages(); const { stopTask } = useChatInteract(); + const isValueEmpty = (val: string | undefined): boolean => { + if (!val) return true; + const cleanedValue = val + .replace(/\s/g, '') // Remove all whitespace + .replace(/\u200B/g, '') // Remove zero-width space + .replace(/\u200C/g, '') // Remove zero-width non-joiner + .replace(/\u200D/g, '') // Remove zero-width joiner + .replace(/\uFEFF/g, ''); // Remove byte order mark + return cleanedValue === ''; + }; + return ( - {loading && firstInteraction ? ( + {!loading && + isValueEmpty(value) && + ((evoya && evoya?.speechToText == true) || evoya == undefined) ? ( + + ) : loading && firstInteraction ? ( @@ -56,9 +80,10 @@ export default function SubmitButton({ disabled={disabled} onClick={onSubmit} size="icon" - className="rounded-full h-8 w-8" + variant="ghost" + className="rounded-full h-8 w-8 hover:bg-muted" > - + diff --git a/frontend/src/components/chat/MessageComposer/UploadButtonDropdown.tsx b/frontend/src/components/chat/MessageComposer/UploadButtonDropdown.tsx new file mode 100644 index 0000000000..b31e614609 --- /dev/null +++ b/frontend/src/components/chat/MessageComposer/UploadButtonDropdown.tsx @@ -0,0 +1,192 @@ +import { FileSpec, useConfig } from '@chainlit/react-client'; + +import { Translator } from '@/components/i18n'; +import { PaperClip } from '@/components/icons/PaperClip'; +import { Button } from '@/components/ui/button'; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger +} from '@/components/ui/tooltip'; + +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger +} from '@/components/ui/dropdown-menu'; +import { + Monitor, + Cloud, +} from 'lucide-react'; + +import { + Dialog, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} from '@/components/ui/dialog'; + +import { useUpload } from '@/hooks/useUpload'; +import FilePicker from '@evoya/file-picker/src/components/FilePicker'; +import { FilePickerItem as FilePickerItemType } from '@evoya/file-picker/src/types'; +import { useState } from 'react'; +import { useRecoilState, useSetRecoilState } from 'recoil'; +import { EvoyaAttachment, evoyaAttachmentsState } from 'state/evoya'; +import { v4 as uuidv4 } from 'uuid'; +import { FilePickerContext } from '@evoya/file-picker/src/context/file-context'; + +interface UploadButtonProps { + disabled?: boolean; + fileSpec: FileSpec; + onFileUpload: (files: File[]) => void; + onFileUploadError: (error: string) => void; +} + +export const UploadButton = ({ + disabled = false, + fileSpec, + onFileUpload, + onFileUploadError +}: UploadButtonProps) => { + const { config } = useConfig(); + const upload = useUpload({ + spec: fileSpec, + onResolved: (payloads: File[]) => onFileUpload(payloads), + onError: onFileUploadError, + options: { noDrag: true } + }); + + const [evoyaAttachments, setEvoyaAttachments] = useRecoilState(evoyaAttachmentsState); + const [filesOpen, setFilesOpen] = useState(false); + const [cloudAttachments, setCloudAttachments] = useState([]); + + const attachFiles = () => { + console.log(cloudAttachments); + const attachements: EvoyaAttachment[] = cloudAttachments.map((item) => { + const id = uuidv4(); + return { + id, + path: item.path, + name: item.name, + type: "size" in item ? item.mime : 'directory', + remove: () => { + setEvoyaAttachments((prev) => + prev.filter((attachment) => attachment.id !== id) + ); + } + } + }) + setEvoyaAttachments((prev) => prev.concat(attachements)); + setFilesOpen(false); + } + + if (!upload) return null; + const { getRootProps, getInputProps } = upload; + + if (!config?.features.spontaneous_file_upload?.enabled) return null; + + return ( + + + + + + + + + + + +
    +
    + +
    +
    + + + + + + +
    +
    +
    + setFilesOpen(true)}> +
    +
    + +
    +
    + + + + + + +
    +
    +
    +
    +
    +
    +
    + + + + + + + +
    + + setCloudAttachments(items)} + multiselect + attachmentMode + /> + +
    + + + + +
    +
    + +

    + +

    +
    +
    +
    + ); +}; + +export default UploadButton; diff --git a/frontend/src/components/chat/MessageComposer/VoiceButton.tsx b/frontend/src/components/chat/MessageComposer/VoiceButton.tsx index b7a98f4bfc..ac093e2a8a 100644 --- a/frontend/src/components/chat/MessageComposer/VoiceButton.tsx +++ b/frontend/src/components/chat/MessageComposer/VoiceButton.tsx @@ -1,5 +1,7 @@ -import { X } from 'lucide-react'; -import { useHotkeys } from 'react-hotkeys-hook'; +import { cn } from '@/lib/utils'; +import { WidgetContext } from 'context'; +import { Check, X, Clock, Mic } from 'lucide-react'; +import { useContext, useEffect, useState } from 'react'; import { useAudio, useConfig } from '@chainlit/react-client'; @@ -22,24 +24,74 @@ interface Props { const VoiceButton = ({ disabled }: Props) => { const { config } = useConfig(); + const { evoya } = useContext(WidgetContext); const { startConversation, endConversation, audioConnection } = useAudio(); + const [modalityType, setModalityType] = useState< + 'realtime' | 'speech' | null + >(null); + const [timeRemaining, setTimeRemaining] = useState(480); + const [timerActive, setTimerActive] = useState(false); + const isEnabled = !!config?.features.audio.enabled; + const isAudioOn = audioConnection === 'on'; + const isAudioOff = audioConnection === 'off'; + const isConnecting = audioConnection === 'connecting'; - useHotkeys( - 'p', - () => { - if (!isEnabled) return; - if (audioConnection === 'on') return endConversation(); - return startConversation(); - }, - [isEnabled, audioConnection, startConversation, endConversation] - ); + const formatTime = (seconds: number): string => { + const minutes = Math.floor(seconds / 60); + const remainingSeconds = seconds % 60; + return `${minutes.toString().padStart(2, '0')}:${remainingSeconds + .toString() + .padStart(2, '0')}`; + }; + + useEffect(() => { + let interval: NodeJS.Timeout | null = null; + + if (isAudioOn && modalityType === 'speech' && timerActive) { + interval = setInterval(() => { + setTimeRemaining((prev) => { + if (prev <= 1) { + endConversation(); + setTimerActive(false); + return 6; + } + return prev - 1; + }); + }, 1000); + } else if (!isAudioOn || modalityType !== 'speech') { + setTimeRemaining(480); + } + + return () => { + if (interval) clearInterval(interval); + }; + }, [isAudioOn, modalityType, timerActive, endConversation]); if (!isEnabled) return null; + const handleToggle = (mode: 'realtime' | 'speech') => { + if (isAudioOn) { + setModalityType(null); + setTimerActive(false); + endConversation(); + } else if (isAudioOff) { + setModalityType(mode); + if (mode === 'speech') { + setTimeRemaining(480); + setTimerActive(true); + } + startConversation(mode); + } + }; + + const getTimerColor = (seconds: number) => { + if (seconds < 60) return 'text-red-500'; + return 'text-muted-foreground'; + }; return (
    - {audioConnection === 'on' ? ( + {isAudioOn && ( { barCount={4} barSpacing={2} /> - ) : null} - - - - - - -

    - -

    -
    -
    -
    + )} + {isAudioOn && modalityType === 'speech' && ( + <> +
    + + {formatTime(timeRemaining)} +
    + + )} + {isAudioOn ? ( + <> + + + + + + +

    + +

    +
    +
    +
    + {modalityType === 'speech' && ( + + + + + + +

    + +

    +
    +
    +
    + )} + + ) : ( + <> + {/* {evoya && evoya.type == 'dashboard' ? ( + + + + + + +

    + +

    +
    +
    +
    + ) : null} */} + + {/* Speech Mode Button */} + {isAudioOff && ( + + + + + + +

    + +

    +
    +
    +
    + )} + + )}
    ); }; + export default VoiceButton; diff --git a/frontend/src/components/chat/MessageComposer/index.tsx b/frontend/src/components/chat/MessageComposer/index.tsx index 99b39a4ed7..5fe03419e3 100644 --- a/frontend/src/components/chat/MessageComposer/index.tsx +++ b/frontend/src/components/chat/MessageComposer/index.tsx @@ -1,12 +1,21 @@ -import { useCallback, useRef, useState } from 'react'; +import { useCallback, useContext, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useRecoilState, useSetRecoilState } from 'recoil'; +import { + useRecoilState, + useRecoilValue, + useResetRecoilState, + useSetRecoilState +} from 'recoil'; import { v4 as uuidv4 } from 'uuid'; +import { WidgetContext } from '@chainlit/copilot/src/context'; +import EvoyaCreatorButton from '@chainlit/copilot/src/evoya/EvoyaCreatorButton'; +import PrivacyShieldToggle from '@chainlit/copilot/src/evoya/privacyShield/PrivacyShieldToggle'; import { FileSpec, ICommand, IStep, + initialTranscriptState, useAuth, useChatData, useChatInteract @@ -17,32 +26,41 @@ import { Button } from '@/components/ui/button'; import { chatSettingsOpenState } from '@/state/project'; import { IAttachment, attachmentsState } from 'state/chat'; +import { evoyaAttachmentsState, EvoyaAttachment } from '@/state/evoya'; import { Attachments } from './Attachments'; import CommandButton from './CommandButton'; import Input, { InputMethods } from './Input'; +import Projects from './Projects'; import SubmitButton from './SubmitButton'; import UploadButton from './UploadButton'; -import VoiceButton from './VoiceButton'; +import UploadButtonDropdown from './UploadButtonDropdown'; interface Props { fileSpec: FileSpec; onFileUpload: (payload: File[]) => void; onFileUploadError: (error: string) => void; setAutoScroll: (autoScroll: boolean) => void; + submitProxy?: (text: string, submitFunction: (text: string) => void) => void; } export default function MessageComposer({ fileSpec, onFileUpload, onFileUploadError, - setAutoScroll + setAutoScroll, + submitProxy }: Props) { + const { evoya } = useContext(WidgetContext); const inputRef = useRef(null); const [value, setValue] = useState(''); const [selectedCommand, setSelectedCommand] = useState(); + const [selectedAgents, setSelectedAgents] = useState([]); const setChatSettingsOpen = useSetRecoilState(chatSettingsOpenState); const [attachments, setAttachments] = useRecoilState(attachmentsState); + const [evoyaAttachments, setEvoyaAttachments] = useRecoilState(evoyaAttachmentsState); + const initialTranscript = useRecoilValue(initialTranscriptState); + const resetInitialTranscript = useResetRecoilState(initialTranscriptState); const { t } = useTranslation(); const { user } = useAuth(); @@ -51,6 +69,18 @@ export default function MessageComposer({ const disabled = _disabled || !!attachments.find((a) => !a.uploaded); + useEffect(() => { + if (!initialTranscript || !inputRef.current) return; + + if (initialTranscript.mode === 'append') { + inputRef.current.appendContent(initialTranscript.text); + } else { + inputRef.current.setContent(initialTranscript.text); + } + + resetInitialTranscript(); + }, [initialTranscript, resetInitialTranscript]); + const onPaste = useCallback((event: ClipboardEvent) => { if (event.clipboardData && event.clipboardData.items) { const items = Array.from(event.clipboardData.items); @@ -71,11 +101,14 @@ export default function MessageComposer({ async ( msg: string, attachments?: IAttachment[], - selectedCommand?: string + evoyaAttachments?: EvoyaAttachment[], + selectedCommand?: string, + selectedAgents?: string[] ) => { const message: IStep = { threadId: '', command: selectedCommand, + agents: selectedAgents, id: uuidv4(), name: user?.identifier || 'User', type: 'user_message', @@ -88,8 +121,20 @@ export default function MessageComposer({ ?.filter((a) => !!a.serverId) .map((a) => ({ id: a.serverId! })); - setAutoScroll(true); - sendMessage(message, fileReferences); + const evoyaReferences = evoyaAttachments + ?.map((a) => ({ path: a.path })); + + if (setAutoScroll) { + setAutoScroll(true); + } + + // @ts-expect-error is not a valid prop + if (window.sendCreatorMessage && window.evoyaCreatorEnabled) { + // @ts-expect-error is not a valid prop + window.sendCreatorMessage(message); + } else { + sendMessage(message, fileReferences, evoyaReferences); + } }, [user, sendMessage] ); @@ -112,16 +157,39 @@ export default function MessageComposer({ [user, replyMessage] ); - const submit = useCallback(() => { - if (disabled || (value === '' && attachments.length === 0)) { + const submit = async () => { + if (submitProxy) { + submitProxy(value, (text: string) => { + if (askUser) { + onReply(text); + } else { + onSubmit(text, attachments, evoyaAttachments); + } + setAttachments([]); + setValue(''); + inputRef.current?.reset(); + }); + } else { + submitMessage(); + } + }; + + const submitMessage = useCallback(() => { + if (disabled || (value === '' && attachments.length === 0 && evoyaAttachments.length === 0)) { return; } + + // Get full content including agents + const fullContent = inputRef.current?.getFullContent?.() || value; + if (askUser) { - onReply(value); + onReply(fullContent); } else { - onSubmit(value, attachments, selectedCommand?.id); + onSubmit(fullContent, attachments, evoyaAttachments, selectedCommand?.id, selectedAgents); } setAttachments([]); + setEvoyaAttachments([]); + setSelectedAgents([]); inputRef.current?.reset(); }, [ value, @@ -129,41 +197,75 @@ export default function MessageComposer({ setValue, askUser, attachments, + evoyaAttachments, selectedCommand, + selectedAgents, setAttachments, + setSelectedAgents, onSubmit ]); return ( -
    - {attachments.length > 0 ? ( +
    + {(attachments.length > 0 || evoyaAttachments.length > 0) ? (
    ) : null} - + {((evoya && evoya?.type == 'dashboard') || evoya == undefined) && ( + + )}
    - - + {(evoya && evoya?.type != 'dashboard') && ( + + )} + {(evoya && evoya?.type == 'dashboard') && ( + + )} + {evoya && evoya?.type == 'dashboard' && ( + <> + + + + )} + {evoya?.evoyaCreator?.enabled && } + {evoya?.api?.privacyShield?.enabled && ( + + )} {chatSettingsInputs.length > 0 && ( )} -
    -
    - + )} +
    +
    diff --git a/frontend/src/components/chat/Messages/Message/Avatar.tsx b/frontend/src/components/chat/Messages/Message/Avatar.tsx index da3054e7e7..76964b7c2b 100644 --- a/frontend/src/components/chat/Messages/Message/Avatar.tsx +++ b/frontend/src/components/chat/Messages/Message/Avatar.tsx @@ -8,20 +8,21 @@ import { } from '@chainlit/react-client'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; -import { Skeleton } from '@/components/ui/skeleton'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; +import BlinkingCursor from '@/components/BlinkingCursor'; interface Props { author?: string; + content?: string; hide?: boolean; } -const MessageAvatar = ({ author, hide }: Props) => { +const MessageAvatar = ({ author, hide, content }: Props) => { const apiClient = useContext(ChainlitContext); const { chatProfile } = useChatSession(); const { config } = useConfig(); @@ -38,19 +39,16 @@ const MessageAvatar = ({ author, hide }: Props) => { return apiClient?.buildEndpoint(`/avatars/${author || 'default'}`); }, [apiClient, selectedChatProfile, config, author]); + const authorInitial = author ? author.charAt(0).toUpperCase() : '?'; + return ( - + - - - - + + + {authorInitial} @@ -59,6 +57,7 @@ const MessageAvatar = ({ author, hide }: Props) => { + {content == '' && } ); }; diff --git a/frontend/src/components/chat/Messages/Message/Buttons/EvoyaCreatorButton.tsx b/frontend/src/components/chat/Messages/Message/Buttons/EvoyaCreatorButton.tsx new file mode 100644 index 0000000000..0c76f082e3 --- /dev/null +++ b/frontend/src/components/chat/Messages/Message/Buttons/EvoyaCreatorButton.tsx @@ -0,0 +1,82 @@ +import { MessageContext } from 'contexts/MessageContext'; + +import { useContext } from 'react'; +import { + type IStep, +} from '@chainlit/react-client'; + +import { PencilLine } from 'lucide-react'; + +import { useTranslation } from '@/components/i18n/Translator'; +import { Button } from '@/components/ui/button'; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger +} from '@/components/ui/tooltip'; +import { Translator } from '@/components/i18n'; + +interface Props { + message: IStep; +} + +function escapeBrackets(text: string) { + const pattern = + /(```[\s\S]*?```|`.*?`)|\\\[([\s\S]*?[^\\])\\\]|\\\((.*?)\\\)|(\${1})/g; + const res = text.replace( + pattern, + (match, codeBlock, squareBracket, roundBracket, dollarSign) => { + if (codeBlock) { + return codeBlock; + } else if (squareBracket) { + return `$$\n${squareBracket}\n$$`; + } else if (roundBracket) { + return `$${roundBracket}$`; + } else if (dollarSign) { + // return '\\$'; + } + return match; + }, + ); + return res; +} + +export function EvoyaCreatorButton({ message }: Props) { + const { showEvoyaCreatorButton } = useContext(MessageContext); + + const handleClick = () => { + // @ts-expect-error custom property + window.openEvoyaCreator({...message, output: escapeBrackets(message.output)}, { type: 'markdown' }); + }; + + if (!showEvoyaCreatorButton) { + return null; + } + + return ( + +
    + + + + + +

    + +

    +
    +
    +
    +
    + ); +}; + +export default EvoyaCreatorButton; diff --git a/frontend/src/components/chat/Messages/Message/Buttons/index.tsx b/frontend/src/components/chat/Messages/Message/Buttons/index.tsx index bebf5a60b6..4da5dd461a 100644 --- a/frontend/src/components/chat/Messages/Message/Buttons/index.tsx +++ b/frontend/src/components/chat/Messages/Message/Buttons/index.tsx @@ -7,8 +7,11 @@ import { import CopyButton from '@/components/CopyButton'; +import { useIsMobile } from '@/hooks/use-mobile'; + import MessageActions from './Actions'; import { DebugButton } from './DebugButton'; +import { EvoyaCreatorButton } from './EvoyaCreatorButton'; import { FeedbackButtons } from './FeedbackButtons'; interface Props { @@ -20,6 +23,7 @@ interface Props { const MessageButtons = ({ message, actions, run }: Props) => { const { config } = useConfig(); const { firstInteraction } = useChatMessages(); + const isMobile = useIsMobile(); const isUser = message.type === 'user_message'; const isAsk = message.waitForAnswer; @@ -40,6 +44,7 @@ const MessageButtons = ({ message, actions, run }: Props) => { return (
    {showCopyButton ? : null} + {!isMobile ? : null} {run ? : null} {messageActions.length ? ( diff --git a/frontend/src/components/chat/Messages/Message/Content/Tools/WebRequest.tsx b/frontend/src/components/chat/Messages/Message/Content/Tools/WebRequest.tsx new file mode 100644 index 0000000000..08dac0b05f --- /dev/null +++ b/frontend/src/components/chat/Messages/Message/Content/Tools/WebRequest.tsx @@ -0,0 +1,42 @@ +import { Card } from '@/components/ui/card'; +import { Item, ItemContent, ItemMedia, ItemTitle } from '@/components/ui/item'; +import type { IStep } from '@chainlit/react-client'; +import { Globe } from 'lucide-react'; +import { useMemo } from 'react'; + +export const WebRequest = ({ step }: { step: IStep }) => { + // const inputJson = JSON.parse(step.input ?? '{}'); + const inputJson = useMemo(() => { + if (step.showInput === "json") { + const json = JSON.parse(step.input ?? '{}'); + console.log(json); + if (json.input && typeof json.input === 'string') { + try { + return JSON.parse(json.input.replace(/'/g, '"')); + } catch(e) { + return { url: 'failed'} + } + } + + return json; + } + + return {}; + }, [step]); + console.log(inputJson); + + return ( + + + + + + + + {inputJson.url ?? 'no url data for web request'} + + + + + ) +} \ No newline at end of file diff --git a/frontend/src/components/chat/Messages/Message/Content/index.tsx b/frontend/src/components/chat/Messages/Message/Content/index.tsx index 49d816cdac..81166176d5 100644 --- a/frontend/src/components/chat/Messages/Message/Content/index.tsx +++ b/frontend/src/components/chat/Messages/Message/Content/index.tsx @@ -1,5 +1,6 @@ import { prepareContent } from '@/lib/message'; -import { memo } from 'react'; +import { memo, useMemo } from 'react'; +import { isEqual } from 'lodash'; import type { IMessageElement, IStep } from '@chainlit/react-client'; @@ -8,6 +9,8 @@ import Markdown from '@/components/Markdown'; import { InlinedElements } from './InlinedElements'; +import { usePrivacyShield } from '@chainlit/copilot/src/evoya/privacyShield/usePrivacyShield'; + export interface Props { elements: IMessageElement[]; message: IStep; @@ -15,6 +18,16 @@ export interface Props { latex?: boolean; } +const getMessageRenderProps = (message: IStep) => ({ + id: message.id, + output: message.output, + input: message.input, + language: message.language, + streaming: message.streaming, + showInput: message.showInput, + type: message.type +}); + const MessageContent = memo( ({ message, elements, allowHtml, latex }: Props) => { const outputContent = @@ -22,6 +35,14 @@ const MessageContent = memo( ? message.output + CURSOR_PLACEHOLDER : message.output; + const { + transformOutput, + } = usePrivacyShield(); + + const messageTrans = useMemo(() => { + return transformOutput(outputContent); + }, [message]) + const { preparedContent: output, inlinedElements: outputInlinedElements, @@ -29,7 +50,7 @@ const MessageContent = memo( } = prepareContent({ elements, id: message.id, - content: outputContent, + content: messageTrans, language: message.language }); @@ -45,7 +66,7 @@ const MessageContent = memo(
    ) : null} @@ -101,6 +122,21 @@ const MessageContent = memo(
    ); + }, + (prevProps, nextProps) => { + return ( + prevProps.allowHtml === nextProps.allowHtml && + prevProps.latex === nextProps.latex && + prevProps.elements === nextProps.elements && + // isEqual( + // prevProps.sections ?? ['input', 'output'], + // nextProps.sections ?? ['input', 'output'] + // ) && + isEqual( + getMessageRenderProps(prevProps.message), + getMessageRenderProps(nextProps.message) + ) + ); } ); diff --git a/frontend/src/components/chat/Messages/Message/Step.tsx b/frontend/src/components/chat/Messages/Message/Step.tsx index bb15a913dd..668ebb083b 100644 --- a/frontend/src/components/chat/Messages/Message/Step.tsx +++ b/frontend/src/components/chat/Messages/Message/Step.tsx @@ -5,6 +5,7 @@ import { PropsWithChildren, useMemo, useState } from 'react'; import type { IStep } from '@chainlit/react-client'; import { Translator } from 'components/i18n'; +import { WebRequest } from './Content/Tools/WebRequest'; interface Props { step: IStep; @@ -26,6 +27,15 @@ export default function Step({ const stepName = step.name; + const renderContent = useMemo(() => { + switch (stepName) { + case "tool_Web_Request": + return + default: + return <>{children} + } + }, [step, children]); + return (

    - {children} + {renderContent}

    )}
    diff --git a/frontend/src/components/chat/Messages/Message/ToolStepInfo.tsx b/frontend/src/components/chat/Messages/Message/ToolStepInfo.tsx new file mode 100644 index 0000000000..36b97df8c2 --- /dev/null +++ b/frontend/src/components/chat/Messages/Message/ToolStepInfo.tsx @@ -0,0 +1,122 @@ +import { cn } from '@/lib/utils'; +import { useMemo } from 'react'; + +import type { IStep } from '@chainlit/react-client'; +import { Translator } from 'components/i18n'; +import { useTranslation } from 'components/i18n/Translator'; + +interface Props { + toolCalls: IStep[]; + isRunning?: boolean; +} + +function humanizeToolName(name: string): string { + const normalizedName = name.replace(/^tool_/, ''); + + if (normalizedName.includes('_')) { + return normalizedName + .split('_') + .filter(Boolean) + .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) + .join(' '); + } + + return normalizedName.replace(/([a-z0-9])([A-Z])/g, '$1 $2'); +} + +function getToolStepInfo(step: IStep): string { + return humanizeToolName(step.name); +} + +function getLatestToolStep(steps: IStep[]): IStep | undefined { + for (let i = steps.length - 1; i >= 0; i--) { + const step = steps[i]; + + if (step.steps?.length) { + const nestedStep = getLatestToolStep(step.steps); + if (nestedStep) { + return nestedStep; + } + } + + if (step.name === 'tools' || step.type === 'tool') { + return step; + } + } +} + +function getStepInfo(step: IStep, { thinkingText, toolText, processingText }: { thinkingText: string, toolText: string, processingText: string}): string { + if (step.type === 'tool' && step.name.includes('DocumentProcessor')) { + return processingText; + } + + if (step.name === 'tools') { + if (!step.steps?.length) { + return toolText; + } + + const latestToolStep = getLatestToolStep(step.steps); + if (latestToolStep) { + return getStepInfo(latestToolStep, { + thinkingText, + toolText, + processingText + }); + } + + return toolText; + } + + if (step.type === 'tool') { + return `${toolText} ${getToolStepInfo(step)}`; + } + + return thinkingText; +} + +export default function ToolStepInfo({ + toolCalls, +}: Props) { + const { t } = useTranslation(); + + // const stepName = step.name; + + const stepInfo = useMemo(() => { + // const isLangGraph = step.name === 'LangGraph' && step.type === 'run'; + + // if (isLangGraph && step.steps && step.steps.length > 0) { + // const currentStepInfo = getStepInfo(step.steps[step.steps.length - 1], t('chat.evoya.cot.thinking'), t('chat.evoya.cot.using_tool')); + + // return currentStepInfo; + // } + const latestToolStep = getLatestToolStep(toolCalls); + + if (latestToolStep) { + const currentStepInfo = getStepInfo( + latestToolStep, + { + thinkingText: t('chat.evoya.cot.thinking'), + toolText: t('chat.evoya.cot.using_tool'), + processingText: t('chat.evoya.cot.processing_document') + } + ); + + return currentStepInfo; + } + + return ; + }, [toolCalls]); + + return ( +
    +

    + {stepInfo} +

    +
    + ); +} diff --git a/frontend/src/components/chat/Messages/Message/UserMessage.tsx b/frontend/src/components/chat/Messages/Message/UserMessage.tsx index 7986fdbb95..ba9c8576b9 100644 --- a/frontend/src/components/chat/Messages/Message/UserMessage.tsx +++ b/frontend/src/components/chat/Messages/Message/UserMessage.tsx @@ -1,6 +1,6 @@ import { cn } from '@/lib/utils'; import { MessageContext } from 'contexts/MessageContext'; -import { useContext, useMemo, useState } from 'react'; +import { memo, useContext, useMemo, useState } from 'react'; import { useSetRecoilState } from 'recoil'; import { @@ -23,7 +23,7 @@ interface Props { elements: IMessageElement[]; } -export default function UserMessage({ +const UserMessage = memo(function UserMessage({ message, elements, children @@ -59,7 +59,6 @@ export default function UserMessage({ editMessage({ ...message, output: editValue }); } }; - return (
    @@ -111,7 +110,11 @@ export default function UserMessage({
    ) : ( -
    +
    {message.command ? (
    {message.command} @@ -124,4 +127,6 @@ export default function UserMessage({
    ); -} +}); + +export default UserMessage; diff --git a/frontend/src/components/chat/Messages/Message/index.tsx b/frontend/src/components/chat/Messages/Message/index.tsx index 15522bc4e9..b128612ad1 100644 --- a/frontend/src/components/chat/Messages/Message/index.tsx +++ b/frontend/src/components/chat/Messages/Message/index.tsx @@ -1,6 +1,6 @@ import { cn } from '@/lib/utils'; import { MessageContext } from 'contexts/MessageContext'; -import { memo, useContext } from 'react'; +import { memo, useContext, useMemo } from 'react'; import { type IAction, @@ -18,9 +18,12 @@ import { MessageButtons } from './Buttons'; import { MessageContent } from './Content'; import Step from './Step'; import UserMessage from './UserMessage'; +import ToolStepInfo from './ToolStepInfo'; interface Props { message: IStep; + toolCalls?: IStep[] | null; + evoyaMode?: string; elements: IMessageElement[]; actions: IAction[]; indent: number; @@ -29,9 +32,19 @@ interface Props { scorableRun?: IStep; } +const EMPTY_ELEMENTS: IMessageElement[] = []; + +const langGraphExclude = ['default', 'dashboard', 'container']; + +const hasVisibleOutput = (output?: string) => { + return !!output?.trim(); +}; + const Message = memo( ({ message, + toolCalls, + evoyaMode, elements, actions, isRunning, @@ -39,6 +52,7 @@ const Message = memo( isScorable, scorableRun }: Props) => { + const { allowHtml, cot, latex, onError } = useContext(MessageContext); const layoutMaxWidth = useLayoutMaxWidth(); const isAsk = message.waitForAnswer; @@ -52,6 +66,18 @@ const Message = memo( const skip = toolCallSkip || hiddenSkip; + const userMessageContent = useMemo( + () => ( + + ), + [message, allowHtml, latex] + ); + if (skip) { if (!message.steps) { return null; @@ -68,6 +94,10 @@ const Message = memo( ); } + if (isStep && message.name === 'Reinforcement') return null; + if (isStep && message.type === 'tool' && message.name.includes('DocumentProcessor')) return null; + if (isStep && message.name === 'LangGraph' && (langGraphExclude.includes(evoyaMode ?? '') || isRunning)) return null; + return ( <>
    @@ -85,18 +115,24 @@ const Message = memo( {isUserMessage ? (
    - + {userMessageContent}
    ) : (
    {!isStep || !indent ? ( - +
    + +
    + ) : null} + {(isRunning || (toolCalls && toolCalls.length > 0)) && + !hasVisibleOutput(message.output) && + evoyaMode !== 'default' ? ( + ) : null} {/* Display the step and its children */} {isStep ? ( diff --git a/frontend/src/components/chat/Messages/index.tsx b/frontend/src/components/chat/Messages/index.tsx index 8cea971059..cd6328803c 100644 --- a/frontend/src/components/chat/Messages/index.tsx +++ b/frontend/src/components/chat/Messages/index.tsx @@ -1,5 +1,5 @@ import { MessageContext } from 'contexts/MessageContext'; -import React, { memo, useContext } from 'react'; +import React, { memo, useContext, useState, useEffect } from 'react'; import { type IAction, @@ -10,6 +10,9 @@ import { import BlinkingCursor from '@/components/BlinkingCursor'; import { Message } from './Message'; +import { WidgetContext } from '@chainlit/copilot/src/context'; +import { firstUserInteraction, } from '@chainlit/react-client'; +import { useRecoilValue } from 'recoil'; interface Props { messages: IStep[]; @@ -38,9 +41,45 @@ const hasAssistantMessage = (step: IStep): boolean => { ); }; +const checkToolStep = (step: IStep): boolean => { + return step.steps?.some((s) => s.type === 'tool' && s.end == null || checkToolStep(s)) || false; +}; + +const collectToolCallSteps = (steps: IStep[]): IStep[] => { + const toolSteps: IStep[] = []; + + for (const step of steps) { + if (step.name === 'tools' || step.type === 'tool') { + toolSteps.push(step); + } + + if (step.steps?.length) { + toolSteps.push(...collectToolCallSteps(step.steps)); + } + } + + return toolSteps; +}; + const Messages = memo( ({ messages, elements, actions, indent, isRunning, scorableRun }: Props) => { + const { evoya } = useContext(WidgetContext); const messageContext = useContext(MessageContext); + const firstInteraction = useRecoilValue(firstUserInteraction); + const [isToolLoading, setToolLoading] = useState(false); + + useEffect(() => { + const getLoaderState = messages.some(checkToolStep); + if (isToolLoading || getLoaderState) { + setToolLoading(false); + } + const timeout = setTimeout(() => { + setToolLoading(getLoaderState); + }, 700); + return () => clearTimeout(timeout); + + }, [messages]); + return ( <> {messages.map((m) => { @@ -73,8 +112,12 @@ const Messages = memo( /> ) : null} {showToolCoTLoader || showHiddenCoTLoader ? ( - +
    + +
    + ) : null} + ); } else { @@ -94,9 +137,17 @@ const Messages = memo( const isScorable = isRunLastAssistantMessage || isLastAssistantMessage; + const toolCalls: IStep[] = []; + + if (indent === 0 && m.type === 'assistant_message') { + toolCalls.push(...collectToolCallSteps(messages)); + } + return ( { const { uploadFile: _uploadFile } = useChatInteract(); const setMessages = useSetRecoilState(messagesState); const setSideView = useSetRecoilState(sideViewState); + const creatorEnabled = useRecoilValue(evoyaCreatorEnabledState); const { t } = useTranslation(); @@ -123,6 +125,7 @@ const MessagesContainer = ({ navigate }: Props) => { allowHtml: config?.features?.unsafe_allow_html, latex: config?.features?.latex, loading, + showEvoyaCreatorButton: config?.showEvoyaCreatorButton && !creatorEnabled, showFeedbackButtons: enableFeedback, uiName: config?.ui?.name || '', cot: config?.ui?.cot || 'hidden', @@ -142,7 +145,6 @@ const MessagesContainer = ({ navigate }: Props) => { onError, onFeedbackUpdated ]); - return ( void; - autoScroll?: boolean; + autoScrollUserMessage?: boolean; + autoScrollRef?: MutableRefObject; children: React.ReactNode; className?: string; } export default function ScrollContainer({ - setAutoScroll, - autoScroll, + autoScrollRef, + autoScrollUserMessage, children, className }: Props) { const ref = useRef(null); + const spacerRef = useRef(null); + const lastUserMessageRef = useRef(null); const { messages } = useChatMessages(); - const { session } = useChatSession(); + const [showScrollButton, setShowScrollButton] = useState(false); + const [isScrolling, setIsScrolling] = useState(false); - useEffect(() => { - setAutoScroll?.(true); - }, [session?.socket.id]); + const scrollToPosition = useCallback(() => { + if (!ref.current || !lastUserMessageRef.current) return; + + setIsScrolling(true); + const scrollPosition = lastUserMessageRef.current.offsetTop - 20; + + ref.current.scrollTo({ + top: scrollPosition, + behavior: 'smooth' + }); + + setShowScrollButton(false); + // We don't know when smooth scroll ends, so we just let handleScroll + // update state as the user interacts. + }, []); + + const scrollToBottom = useCallback(() => { + if (!ref.current) return; + + setIsScrolling(true); + ref.current.scrollTo({ + top: ref.current.scrollHeight, + behavior: 'smooth' + }); + + if (autoScrollRef) { + autoScrollRef.current = true; + } + + setShowScrollButton(false); + }, [autoScrollRef]); + + // Calculate and update spacer height + const updateSpacerHeight = useCallback(() => { + if (!ref.current) return; + // When focusing on the last user message + if (autoScrollUserMessage && lastUserMessageRef.current) { + const containerHeight = ref.current.clientHeight; + const lastMessageHeight = lastUserMessageRef.current.offsetHeight; + + // Height of all elements after the last user message + let afterMessagesHeight = 0; + let currentElement = lastUserMessageRef.current.nextElementSibling; + + while (currentElement && currentElement !== spacerRef.current) { + afterMessagesHeight += (currentElement as HTMLElement).offsetHeight; + currentElement = currentElement.nextElementSibling; + } + + const newSpacerHeight = + containerHeight - lastMessageHeight - afterMessagesHeight - 32; + + if (spacerRef.current) { + spacerRef.current.style.height = `${Math.max(0, newSpacerHeight)}px`; + } + + // If nothing after the last user message, scroll to it. + if (afterMessagesHeight === 0) { + scrollToPosition(); + } else { + // Otherwise, follow the normal auto-scroll behavior. + if (!autoScrollRef || autoScrollRef.current) { + ref.current.scrollTop = ref.current.scrollHeight; + } + } + } else { + // Normal behavior: keep at bottom if auto-scroll is enabled or no ref passed + if (!autoScrollRef || autoScrollRef.current) { + ref.current.scrollTop = ref.current.scrollHeight; + } + } + }, [autoScrollUserMessage, autoScrollRef, scrollToPosition]); + + // Find and set a ref to the last user message element useEffect(() => { - if (!ref.current || !autoScroll) { + if (!ref.current) return; + + if (messages.length === 0 && spacerRef.current) { + spacerRef.current.style.height = `0px`; return; } - ref.current.scrollTop = ref.current.scrollHeight; - }, [messages, autoScroll]); + + const userMessages = ref.current.querySelectorAll( + '[data-step-type="user_message"]' + ); + + if (userMessages.length > 0) { + const lastUserMessage = userMessages[ + userMessages.length - 1 + ] as HTMLDivElement; + + lastUserMessageRef.current = lastUserMessage; + + // Delay a bit to ensure DOM layout is updated + requestAnimationFrame(() => { + updateSpacerHeight(); + }); + } else if (autoScrollRef?.current && ref.current) { + // No user messages, just keep at bottom if needed + ref.current.scrollTop = ref.current.scrollHeight; + } + }, [messages, updateSpacerHeight, autoScrollRef]); + + // Window resize listener to update spacer height + useEffect(() => { + if (!autoScrollUserMessage) return; + + const handleResize = () => { + updateSpacerHeight(); + }; + + window.addEventListener('resize', handleResize); + + // Initial update + updateSpacerHeight(); + + return () => { + window.removeEventListener('resize', handleResize); + }; + }, [autoScrollUserMessage, updateSpacerHeight]); + + // Check scroll position on mount + useEffect(() => { + if (!ref.current) return; + + setTimeout(() => { + if (!ref.current) return; + + const { scrollTop, scrollHeight, clientHeight } = ref.current; + const atBottom = scrollTop + clientHeight >= scrollHeight - 10; + setShowScrollButton(!atBottom); + if (autoScrollRef) { + autoScrollRef.current = atBottom; + } + }, 300); + }, [autoScrollRef]); const handleScroll = () => { - if (!ref.current || !setAutoScroll) return; + if (!ref.current) return; const { scrollTop, scrollHeight, clientHeight } = ref.current; const atBottom = scrollTop + clientHeight >= scrollHeight - 10; - setAutoScroll(atBottom); + + if (autoScrollRef) { + autoScrollRef.current = atBottom; + } + + setShowScrollButton(!atBottom); + setIsScrolling(false); }; return ( -
    - {children} +
    +
    + {children} + {/* Dynamic spacer to position the last user message at the top */} +
    +
    + + {showScrollButton ? ( +
    + +
    + ) : null}
    ); } diff --git a/frontend/src/components/chat/WelcomeScreen.tsx b/frontend/src/components/chat/WelcomeScreen.tsx index bf5356b33f..5857a7d247 100644 --- a/frontend/src/components/chat/WelcomeScreen.tsx +++ b/frontend/src/components/chat/WelcomeScreen.tsx @@ -72,11 +72,10 @@ export default function WelcomeScreen(props: Props) { return (
    - {logo}
    diff --git a/frontend/src/components/chat/index.tsx b/frontend/src/components/chat/index.tsx index 6b39f751f5..0c4bba14a4 100644 --- a/frontend/src/components/chat/index.tsx +++ b/frontend/src/components/chat/index.tsx @@ -35,7 +35,9 @@ const Chat = () => { const setAttachments = useSetRecoilState(attachmentsState); const setThreads = useSetRecoilState(threadHistoryState); + const autoScrollRef = useRef(true); const [autoScroll, setAutoScroll] = useState(true); + const { error, disabled } = useChatData(); const { uploadFile } = useChatInteract(); const uploadFileRef = useRef(uploadFile); @@ -200,7 +202,10 @@ const Chat = () => {
    ) : null} - +
    { fileSpec={fileSpec} onFileUpload={onFileUpload} onFileUploadError={onFileUploadError} + autoScrollRef={autoScrollRef} setAutoScroll={setAutoScroll} autoScroll={autoScroll} /> diff --git a/frontend/src/components/header/ChatProfiles.tsx b/frontend/src/components/header/ChatProfiles.tsx index 4aeab50246..8f1093a965 100644 --- a/frontend/src/components/header/ChatProfiles.tsx +++ b/frontend/src/components/header/ChatProfiles.tsx @@ -22,7 +22,6 @@ import { SelectValue } from '@/components/ui/select'; -import { NewChatDialog } from './NewChat'; interface Props { navigate?: (to: string) => void; diff --git a/frontend/src/components/header/NewChat.tsx b/frontend/src/components/header/NewChat.tsx index 184e917a18..b64bb5619c 100644 --- a/frontend/src/components/header/NewChat.tsx +++ b/frontend/src/components/header/NewChat.tsx @@ -1,109 +1,88 @@ -import React, { useState } from 'react'; +import { WidgetContext } from 'context'; +import { Plus } from 'lucide-react'; +import React, { useContext } from 'react'; -import { useChatInteract } from '@chainlit/react-client'; +import { + ChainlitContext, + useAudio, + useAuth, + useChatInteract, + useChatSession +} from '@chainlit/react-client'; import { Translator } from '@/components/i18n'; import { Button } from '@/components/ui/button'; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle -} from '@/components/ui/dialog'; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger -} from '@/components/ui/tooltip'; - -import { EditSquare } from '../icons/EditSquare'; -type NewChatDialogProps = { - open: boolean; - handleClose: () => void; - handleConfirm: () => void; -}; - -export const NewChatDialog = ({ - open, - handleClose, - handleConfirm -}: NewChatDialogProps) => { - return ( - - - - - - - - - - - - - - - - - ); -}; +import { useIsMobile } from '@/hooks/use-mobile'; interface Props extends React.ButtonHTMLAttributes { - navigate?: (to: string) => void; + newSession?: (sessionUuid?: string) => void; } -const NewChatButton = ({ navigate, ...buttonProps }: Props) => { - const [open, setOpen] = useState(false); +const NewChatButton = ({ newSession }: Props) => { const { clear } = useChatInteract(); + const { evoya, setAccessToken } = useContext(WidgetContext); + const apiClient = useContext(ChainlitContext); + const { setUserFromAPI } = useAuth(); - const handleClickOpen = () => { - setOpen(true); - }; + const { endConversation, audioConnection } = useAudio(); + const isAudioOn = audioConnection === 'on'; + const isMobile = useIsMobile(); - const handleClose = () => { - setOpen(false); - }; + const handleClickOpen = async () => { + localStorage.removeItem('session_token'); + document.cookie = + 'session_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; + window.dispatchEvent(new CustomEvent('copilot-new-session')); + + if (isAudioOn) { + endConversation(); + } - const handleConfirm = () => { clear(); - navigate?.('/'); - handleClose(); + + if (evoya?.reset) { + return; + } + + if (evoya?.getEvoyaAccessToken && evoya?.chat_uuid) { + try { + const newAccessToken = await evoya.getEvoyaAccessToken( + evoya.chat_uuid, + undefined, + {} + ); + if (newAccessToken) { + localStorage.setItem('chainlit_token', newAccessToken); + setAccessToken(newAccessToken); + apiClient + .jwtAuth(newAccessToken) + .then((res) => setUserFromAPI()) + .catch((err) => console.log(err)); + } + } catch (error) { + console.error('Failed to get new access token:', error); + } + } + + newSession?.(''); }; return (
    - - - - - - - - - - - +
    ); }; diff --git a/frontend/src/components/i18n/Translator.tsx b/frontend/src/components/i18n/Translator.tsx index 8681f88f86..14f2a09e82 100644 --- a/frontend/src/components/i18n/Translator.tsx +++ b/frontend/src/components/i18n/Translator.tsx @@ -10,9 +10,10 @@ type TranslatorProps = { path: string | string[]; suffix?: string; options?: options; + className?: string; }; -const Translator = ({ path, options, suffix }: TranslatorProps) => { +const Translator = ({ path, options, suffix, className }: TranslatorProps) => { const { t, i18n } = usei18nextTranslation(); if (!i18n.exists(path, options)) { @@ -20,7 +21,7 @@ const Translator = ({ path, options, suffix }: TranslatorProps) => { } return ( - + {t(path, options)} {suffix} diff --git a/frontend/src/components/ui/button.tsx b/frontend/src/components/ui/button.tsx index 6e5dd42c2e..ea7cd781bc 100644 --- a/frontend/src/components/ui/button.tsx +++ b/frontend/src/components/ui/button.tsx @@ -16,13 +16,15 @@ const buttonVariants = cva( secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80', ghost: 'hover:bg-accent hover:text-accent-foreground', + 'ghost-destructive': 'hover:bg-destructive/10 text-destructive', link: 'text-primary underline-offset-4 hover:underline' }, size: { default: 'h-10 px-4 py-2', sm: 'h-9 rounded-md px-3', lg: 'h-11 rounded-md px-8', - icon: 'h-9 w-9' + icon: 'h-9 w-9', + xs: 'h-6 w-6 rounded-sm' } }, defaultVariants: { diff --git a/frontend/src/components/ui/checkbox.tsx b/frontend/src/components/ui/checkbox.tsx index 2b7815b970..5984516423 100644 --- a/frontend/src/components/ui/checkbox.tsx +++ b/frontend/src/components/ui/checkbox.tsx @@ -10,7 +10,7 @@ const Checkbox = React.forwardRef< , React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( -
    +
    , - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( + React.ComponentPropsWithoutRef & { container?: Element | DocumentFragment} +>(({ className, container, children, ...props }, ref) => ( diff --git a/frontend/src/components/ui/dropdown-menu.tsx b/frontend/src/components/ui/dropdown-menu.tsx index 9e4c69c0e4..44c8414bcb 100644 --- a/frontend/src/components/ui/dropdown-menu.tsx +++ b/frontend/src/components/ui/dropdown-menu.tsx @@ -57,12 +57,16 @@ const DropdownMenuContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, sideOffset = 4, ...props }, ref) => ( - + , React.ComponentPropsWithoutRef & { - inset?: boolean; + inset?: boolean } >(({ className, inset, ...props }, ref) => ( -)); +)) DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; const DropdownMenuCheckboxItem = React.forwardRef< @@ -102,7 +106,7 @@ const DropdownMenuCheckboxItem = React.forwardRef< checked={checked} {...props} > - + @@ -159,7 +163,7 @@ const DropdownMenuSeparator = React.forwardRef< >(({ className, ...props }, ref) => ( )); diff --git a/frontend/src/components/ui/input-group.tsx b/frontend/src/components/ui/input-group.tsx new file mode 100644 index 0000000000..e4205769a3 --- /dev/null +++ b/frontend/src/components/ui/input-group.tsx @@ -0,0 +1,168 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Textarea } from "@/components/ui/textarea" + +function InputGroup({ className, ...props }: React.ComponentProps<"div">) { + return ( +
    textarea]:h-auto", + + // Variants based on alignment. + "has-[>[data-align=inline-start]]:[&>input]:pl-2", + "has-[>[data-align=inline-end]]:[&>input]:pr-2", + "has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3", + "has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3", + + // Focus state. + "has-[[data-slot=input-group-control]:focus-visible]:ring-ring has-[[data-slot=input-group-control]:focus-visible]:ring-1", + + // Error state. + "has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40", + + className + )} + {...props} + /> + ) +} + +const inputGroupAddonVariants = cva( + "text-muted-foreground flex h-auto cursor-text select-none items-center justify-center gap-2 py-1.5 text-sm font-medium group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4", + { + variants: { + align: { + "inline-start": + "order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]", + "inline-end": + "order-last pr-3 has-[>button]:mr-[-0.4rem] has-[>kbd]:mr-[-0.35rem]", + "block-start": + "[.border-b]:pb-3 order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5", + "block-end": + "[.border-t]:pt-3 order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5", + }, + }, + defaultVariants: { + align: "inline-start", + }, + } +) + +function InputGroupAddon({ + className, + align = "inline-start", + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
    { + if ((e.target as HTMLElement).closest("button")) { + return + } + e.currentTarget.parentElement?.querySelector("input")?.focus() + }} + {...props} + /> + ) +} + +const inputGroupButtonVariants = cva( + "flex items-center gap-2 text-sm shadow-none", + { + variants: { + size: { + xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5", + sm: "h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5", + "icon-xs": + "size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0", + "icon-sm": "size-8 p-0 has-[>svg]:p-0", + }, + }, + defaultVariants: { + size: "xs", + }, + } +) + +function InputGroupButton({ + className, + type = "button", + variant = "ghost", + size = "xs", + ...props +}: Omit, "size"> & + VariantProps) { + return ( +