From ba4bb63a1f4466bc1ae532ad3cdb8e7d1567577c Mon Sep 17 00:00:00 2001 From: asminkarki012 Date: Fri, 4 Apr 2025 18:36:45 +0545 Subject: [PATCH 01/26] feat[mermaid]:integration of mermaid --- frontend/package-lock.json | 1311 ++++++++++++++++- frontend/package.json | 2 + frontend/src/components/MermaidRenderer.tsx | 297 ++++ .../src/conversation/ConversationBubble.tsx | 35 +- 4 files changed, 1626 insertions(+), 19 deletions(-) create mode 100644 frontend/src/components/MermaidRenderer.tsx diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d70a202f..884d9adc 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,6 +12,7 @@ "chart.js": "^4.4.4", "i18next": "^24.2.0", "i18next-browser-languagedetector": "^8.0.2", + "mermaid": "^11.6.0", "prop-types": "^15.8.1", "react": "^18.2.0", "react-chartjs-2": "^5.3.0", @@ -29,6 +30,7 @@ "remark-math": "^6.0.0" }, "devDependencies": { + "@types/mermaid": "^9.1.0", "@types/react": "^18.0.27", "@types/react-dom": "^18.3.0", "@types/react-helmet": "^6.1.11", @@ -82,6 +84,28 @@ "node": ">=6.0.0" } }, + "node_modules/@antfu/install-pkg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.0.0.tgz", + "integrity": "sha512-xvX6P/lo1B3ej0OsaErAjqgFYzYVcJpamjLAFLYh9vRJngBrMoUG7aVnrGTeqM7yxbyTD5p3F2+0/QUEh8Vzhw==", + "license": "MIT", + "dependencies": { + "package-manager-detector": "^0.2.8", + "tinyexec": "^0.3.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@antfu/utils": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-8.1.1.tgz", + "integrity": "sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/@babel/code-frame": { "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", @@ -361,6 +385,51 @@ "node": ">=6.9.0" } }, + "node_modules/@braintree/sanitize-url": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.1.tgz", + "integrity": "sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==", + "license": "MIT" + }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", + "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/gast": "11.0.3", + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/gast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", + "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", + "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/types": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", + "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/utils": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", + "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", + "license": "Apache-2.0" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -835,6 +904,40 @@ "deprecated": "Use @eslint/object-schema instead", "dev": true }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.3.0.tgz", + "integrity": "sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==", + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^1.0.0", + "@antfu/utils": "^8.1.0", + "@iconify/types": "^2.0.0", + "debug": "^4.4.0", + "globals": "^15.14.0", + "kolorist": "^1.8.0", + "local-pkg": "^1.0.0", + "mlly": "^1.7.4" + } + }, + "node_modules/@iconify/utils/node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -971,6 +1074,15 @@ "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" }, + "node_modules/@mermaid-js/parser": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.4.0.tgz", + "integrity": "sha512-wla8XOWvQAwuqy+gxiZqY+c7FokraOTHRWMsbB4AgRx9Sy7zKslNyejy7E+a77qHfey5GXw/ik3IXv/NHMJgaA==", + "license": "MIT", + "dependencies": { + "langium": "3.3.1" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1547,6 +1659,259 @@ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==" }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==", + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz", + "integrity": "sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==", + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -1568,6 +1933,12 @@ "@types/estree": "*" } }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, "node_modules/@types/hast": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", @@ -1611,6 +1982,13 @@ "@types/unist": "*" } }, + "node_modules/@types/mermaid": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@types/mermaid/-/mermaid-9.1.0.tgz", + "integrity": "sha512-rc8QqhveKAY7PouzY/p8ljS+eBSNCv7o79L97RSub/Ic2SQ34ph1Ng3s8wFLWVjvaEt6RLOWtSCsgYWd95NY8A==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/ms": { "version": "0.7.34", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", @@ -1635,7 +2013,7 @@ "version": "18.3.0", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", - "dev": true, + "devOptional": true, "dependencies": { "@types/react": "*" } @@ -1670,6 +2048,13 @@ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -2078,10 +2463,10 @@ } }, "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true, + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -2684,6 +3069,32 @@ "pnpm": ">=8" } }, + "node_modules/chevrotain": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", + "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", + "license": "Apache-2.0", + "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" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", + "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "license": "MIT", + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^11.0.0" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -2787,6 +3198,12 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "license": "MIT" + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -2809,6 +3226,15 @@ "toggle-selection": "^1.0.6" } }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "license": "MIT", + "dependencies": { + "layout-base": "^1.0.0" + } + }, "node_modules/cosmiconfig": { "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", @@ -2867,6 +3293,514 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, + "node_modules/cytoscape": { + "version": "3.31.2", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.31.2.tgz", + "integrity": "sha512-/eOXg2uGdMdpGlEes5Sf6zE+jUG+05f3htFNQIxLxduOH/SsaUZiPBfAwP1btVIVzsnhiNOdi+hvDRLYfMZjGw==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^2.2.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "license": "MIT", + "dependencies": { + "layout-base": "^2.0.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", + "license": "MIT" + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.11.tgz", + "integrity": "sha512-tvlJLyQf834SylNKax8Wkzco/1ias1OPw8DcUMDE7oUIoSEW25riQVuiu/0OWEFqT0cxHT3Pa9/D82Jr47IONw==", + "license": "MIT", + "dependencies": { + "d3": "^7.9.0", + "lodash-es": "^4.17.21" + } + }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", @@ -2918,6 +3852,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -2986,6 +3926,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -3042,6 +3991,15 @@ "node": ">=6.0.0" } }, + "node_modules/dompurify": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.5.tgz", + "integrity": "sha512-mLPd29uoRe9HpvwP2TxClGQBzGXeEC/we/q+bFlmPPmj2p2Ugl3r6ATu/UU1v77DXNcehiBg9zsr1dREyA/dJQ==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/dot-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", @@ -4063,6 +5021,12 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/exsolve": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.4.tgz", + "integrity": "sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==", + "license": "MIT" + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -4508,6 +5472,12 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "license": "MIT" + }, "node_modules/has-bigints": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", @@ -5003,6 +5973,18 @@ "@babel/runtime": "^7.23.2" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -5081,6 +6063,15 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/is-alphabetical": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", @@ -5685,6 +6676,39 @@ "node": ">= 12" } }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" + }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "license": "MIT" + }, + "node_modules/langium": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/langium/-/langium-3.3.1.tgz", + "integrity": "sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==", + "license": "MIT", + "dependencies": { + "chevrotain": "~11.0.3", + "chevrotain-allstar": "~0.3.0", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "vscode-uri": "~3.0.8" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "license": "MIT" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5760,6 +6784,23 @@ "node": ">=18.0.0" } }, + "node_modules/local-pkg": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.1.tgz", + "integrity": "sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==", + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.0.1", + "quansync": "^0.2.8" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -5775,6 +6816,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5924,6 +6971,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/marked": { + "version": "15.0.7", + "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.7.tgz", + "integrity": "sha512-dgLIeKGLx5FwziAnsk4ONoGwHwGPJzselimvlVskE9XLN4Orv9u2VA3GWw/lYUqjfA0rUT/6fqKwfZJapP9BEg==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -6356,6 +7415,34 @@ "node": ">= 8" } }, + "node_modules/mermaid": { + "version": "11.6.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.6.0.tgz", + "integrity": "sha512-PE8hGUy1LDlWIHWBP05SFdqUHGmRcCcK4IzpOKPE35eOw+G9zZgcnMpyunJVUEOgb//KBORPjysKndw8bFLuRg==", + "license": "MIT", + "dependencies": { + "@braintree/sanitize-url": "^7.0.4", + "@iconify/utils": "^2.1.33", + "@mermaid-js/parser": "^0.4.0", + "@types/d3": "^7.4.3", + "cytoscape": "^3.29.3", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.11", + "dayjs": "^1.11.13", + "dompurify": "^3.2.4", + "katex": "^0.16.9", + "khroma": "^2.1.0", + "lodash-es": "^4.17.21", + "marked": "^15.0.7", + "roughjs": "^4.6.6", + "stylis": "^4.3.6", + "ts-dedent": "^2.2.0", + "uuid": "^11.1.0" + } + }, "node_modules/micromark": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", @@ -6977,6 +8064,35 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mlly": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", + "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "pathe": "^2.0.1", + "pkg-types": "^1.3.0", + "ufo": "^1.5.4" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -7306,6 +8422,15 @@ "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", "dev": true }, + "node_modules/package-manager-detector": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.11.tgz", + "integrity": "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==", + "license": "MIT", + "dependencies": { + "quansync": "^0.2.7" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -7374,6 +8499,12 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -7438,6 +8569,12 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -7486,6 +8623,33 @@ "node": ">= 6" } }, + "node_modules/pkg-types": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz", + "integrity": "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==", + "license": "MIT", + "dependencies": { + "confbox": "^0.2.1", + "exsolve": "^1.0.1", + "pathe": "^2.0.3" + } + }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "license": "MIT" + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "license": "MIT", + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", @@ -7789,6 +8953,22 @@ "node": ">=6" } }, + "node_modules/quansync": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.10.tgz", + "integrity": "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -8384,6 +9564,12 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense" + }, "node_modules/rollup": { "version": "4.22.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz", @@ -8419,6 +9605,18 @@ "fsevents": "~2.3.2" } }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "license": "MIT", + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -8442,6 +9640,12 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, "node_modules/safe-array-concat": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", @@ -8494,6 +9698,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", @@ -8990,6 +10200,12 @@ "inline-style-parser": "0.2.3" } }, + "node_modules/stylis": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", + "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "license": "MIT" + }, "node_modules/sucrase": { "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", @@ -9183,6 +10399,12 @@ "node": ">=0.8" } }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -9218,6 +10440,15 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", @@ -9376,7 +10607,7 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", - "dev": true, + "devOptional": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9385,6 +10616,12 @@ "node": ">=14.17" } }, + "node_modules/ufo": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "license": "MIT" + }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", @@ -9564,6 +10801,19 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, "node_modules/vfile": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.2.tgz", @@ -9688,6 +10938,55 @@ "node": ">=0.10.0" } }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "license": "MIT" + }, "node_modules/web-namespaces": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 89a55b04..80887ce4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -23,6 +23,7 @@ "chart.js": "^4.4.4", "i18next": "^24.2.0", "i18next-browser-languagedetector": "^8.0.2", + "mermaid": "^11.6.0", "prop-types": "^15.8.1", "react": "^18.2.0", "react-chartjs-2": "^5.3.0", @@ -40,6 +41,7 @@ "remark-math": "^6.0.0" }, "devDependencies": { + "@types/mermaid": "^9.1.0", "@types/react": "^18.0.27", "@types/react-dom": "^18.3.0", "@types/react-helmet": "^6.1.11", diff --git a/frontend/src/components/MermaidRenderer.tsx b/frontend/src/components/MermaidRenderer.tsx new file mode 100644 index 00000000..569dfdc2 --- /dev/null +++ b/frontend/src/components/MermaidRenderer.tsx @@ -0,0 +1,297 @@ +import React, { useEffect, useRef, useState } from 'react'; +import mermaid from 'mermaid'; +import CopyButton from './CopyButton'; +import { useSelector } from 'react-redux'; +import { selectStatus } from '../conversation/conversationSlice'; + +interface MermaidRendererProps { + code: string; + isDarkTheme: boolean; +} + +const MermaidRenderer: React.FC = ({ + code, + isDarkTheme, +}) => { + const containerRef = useRef(null); + const status = useSelector(selectStatus); + const [svgContent, setSvgContent] = useState(''); + const [error, setError] = useState(null); + const [showCode, setShowCode] = useState(false); + const [showDownloadMenu, setShowDownloadMenu] = useState(false); + const downloadMenuRef = useRef(null); + + useEffect(() => { + if (status === 'loading' || !code) return; + // Initialize mermaid with the current theme + mermaid.initialize({ + startOnLoad: false, + theme: isDarkTheme ? 'dark' : 'default', + securityLevel: 'loose', + }); + const renderDiagram = async (): Promise => { + try { + // Generate unique ID + const id = `mermaid-${Math.random().toString(36).substring(2, 9)}`; + + // Render the diagram + const { svg } = await mermaid.render(id, code); + setSvgContent(svg); + setError(null); + } catch (err) { + console.error('Mermaid rendering error:', err); + setError( + `Failed to render Mermaid diagram: ${err instanceof Error ? err.message : String(err)}`, + ); + setSvgContent(''); + } + }; + + renderDiagram(); + }, [code, isDarkTheme, status]); + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + downloadMenuRef.current && + !downloadMenuRef.current.contains(event.target as Node) + ) { + setShowDownloadMenu(false); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [showDownloadMenu]); + + // Function to download as SVG + const downloadSvg = (): void => { + if (!svgContent) return; + + // Add XML declaration and ensure proper namespaces + let enhancedSvg = svgContent; + if (!enhancedSvg.includes('xmlns=')) { + enhancedSvg = enhancedSvg.replace( + ' { + if (!svgContent) return; + + // Parse the SVG + const parser = new DOMParser(); + const svgDoc = parser.parseFromString(svgContent, 'image/svg+xml'); + const svgElement = svgDoc.documentElement; + + // Ensure SVG has dimensions + let width = parseInt(svgElement.getAttribute('width') || '0'); + let height = parseInt(svgElement.getAttribute('height') || '0'); + + // If dimensions are missing, try to get from viewBox + if (!width || !height) { + const viewBox = svgElement.getAttribute('viewBox')?.split(' ') || []; + if (viewBox.length === 4) { + width = parseInt(viewBox[2]); + height = parseInt(viewBox[3]); + svgElement.setAttribute('width', width.toString()); + svgElement.setAttribute('height', height.toString()); + } else { + width = 800; + height = 600; + svgElement.setAttribute('width', width.toString()); + svgElement.setAttribute('height', height.toString()); + } + } + + const serializer = new XMLSerializer(); + const svgString = serializer.serializeToString(svgDoc); + + // Create an Image object + const img = new Image(); + + img.onload = function (): void { + // Create a canvas with proper dimensions + const canvas = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + + const ctx = canvas.getContext('2d'); + if (!ctx) { + console.error('Could not get canvas context'); + return; + } + + // Fill with white background + ctx.fillStyle = '#ffffff'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + // Draw the image + ctx.drawImage(img, 0, 0, width, height); + + // Convert to PNG and download + const pngUrl = canvas.toDataURL('image/png'); + const link = document.createElement('a'); + link.download = 'diagram.png'; + link.href = pngUrl; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + }; + + // Set the image source to the SVG + const svgBlob = new Blob([svgString], { type: 'image/svg+xml' }); + const url = URL.createObjectURL(svgBlob); + img.src = url; + }; + + const downloadMmd = (): void => { + const blob = new Blob([code], { type: 'text/plain' }); + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = 'diagram.mmd'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); + }; + + const downloadOptions = [ + { label: 'Download as SVG', action: downloadSvg }, + { label: 'Download as PNG', action: downloadPng }, + { label: 'Download as MMD', action: downloadMmd }, + ]; + + const showDiagramOptions = status !== 'loading' && !error; + const errorRender = status !== 'loading' && error; + + return ( +
+
+ + mermaid + +
+ + + {showDiagramOptions && ( +
+ + {showDownloadMenu && ( +
+
    + {downloadOptions.map((option, index) => ( +
  • + +
  • + ))} +
+
+ )} +
+ )} + + {showDiagramOptions && ( + + )} +
+
+ + {status === 'loading' ? ( +
+
+ Loading diagram... +
+
+ ) : errorRender ? ( +
+
+ {error} +
+ {/*
+            {code}
+          
*/} +
+ ) : ( +
+ {/* Show the diagram */} +
+ + {/* Show the code when button is clicked */} + {showCode && ( +
+              {code}
+            
+ )} +
+ )} +
+ ); +}; + +export default MermaidRenderer; diff --git a/frontend/src/conversation/ConversationBubble.tsx b/frontend/src/conversation/ConversationBubble.tsx index ec244087..0b7498d2 100644 --- a/frontend/src/conversation/ConversationBubble.tsx +++ b/frontend/src/conversation/ConversationBubble.tsx @@ -36,6 +36,7 @@ import { import classes from './ConversationBubble.module.css'; import { FEEDBACK, MESSAGE_TYPE } from './conversationModels'; import { ToolCallsType } from './types'; +import MermaidRenderer from '../components/MermaidRenderer'; const DisableSourceFE = import.meta.env.VITE_DISABLE_SOURCE_FE || false; @@ -101,26 +102,25 @@ const ConversationBubble = forwardRef< let bubble; const renderAttachments = () => { if (!attachments || attachments.length === 0) return null; - return (
{attachments.map((attachment, index) => ( -
- - {attachment.fileName} @@ -792,6 +792,15 @@ function Thought({ const match = /language-(\w+)/.exec(className || ''); const language = match ? match[1] : ''; + if (language === 'mermaid') { + return ( + + ); + } + return match ? (
From b1235f3ce0812b842d27413597e67ddc9bd11a50 Mon Sep 17 00:00:00 2001 From: asminkarki012 Date: Fri, 4 Apr 2025 18:40:57 +0545 Subject: [PATCH 02/26] feat[mermaid]:clean comment --- frontend/src/components/MermaidRenderer.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/frontend/src/components/MermaidRenderer.tsx b/frontend/src/components/MermaidRenderer.tsx index 569dfdc2..d3fda1d4 100644 --- a/frontend/src/components/MermaidRenderer.tsx +++ b/frontend/src/components/MermaidRenderer.tsx @@ -267,9 +267,6 @@ const MermaidRenderer: React.FC = ({
{error}
- {/*
-            {code}
-          
*/}
) : (
From c5a8f3abcdee1ec45f83e72b37cef8103f87a436 Mon Sep 17 00:00:00 2001 From: asminkarki012 Date: Fri, 11 Apr 2025 11:48:07 +0545 Subject: [PATCH 03/26] refact:generate unique meraid id using crypto.randomUUID --- frontend/src/components/MermaidRenderer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/MermaidRenderer.tsx b/frontend/src/components/MermaidRenderer.tsx index d3fda1d4..23b69155 100644 --- a/frontend/src/components/MermaidRenderer.tsx +++ b/frontend/src/components/MermaidRenderer.tsx @@ -32,7 +32,7 @@ const MermaidRenderer: React.FC = ({ const renderDiagram = async (): Promise => { try { // Generate unique ID - const id = `mermaid-${Math.random().toString(36).substring(2, 9)}`; + const id = `mermaid-${crypto.randomUUID()}`; // Render the diagram const { svg } = await mermaid.render(id, code); From ea0aa64330669abd67bca01fb53c66ca93eda5a8 Mon Sep 17 00:00:00 2001 From: asminkarki012 Date: Mon, 21 Apr 2025 20:50:04 +0545 Subject: [PATCH 04/26] fix: added renderer in answer bubble --- frontend/src/components/MermaidRenderer.tsx | 6 +----- frontend/src/components/types/index.ts | 5 +++++ .../src/conversation/ConversationBubble.tsx | 18 +++++++++--------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/MermaidRenderer.tsx b/frontend/src/components/MermaidRenderer.tsx index 23b69155..c32b253b 100644 --- a/frontend/src/components/MermaidRenderer.tsx +++ b/frontend/src/components/MermaidRenderer.tsx @@ -3,11 +3,7 @@ import mermaid from 'mermaid'; import CopyButton from './CopyButton'; import { useSelector } from 'react-redux'; import { selectStatus } from '../conversation/conversationSlice'; - -interface MermaidRendererProps { - code: string; - isDarkTheme: boolean; -} +import { MermaidRendererProps } from './types'; const MermaidRenderer: React.FC = ({ code, diff --git a/frontend/src/components/types/index.ts b/frontend/src/components/types/index.ts index 47fcd86f..4e6870c4 100644 --- a/frontend/src/components/types/index.ts +++ b/frontend/src/components/types/index.ts @@ -22,3 +22,8 @@ export type InputProps = { e: React.KeyboardEvent, ) => void; }; + +export type MermaidRendererProps = { + code: string; + isDarkTheme: boolean; +}; diff --git a/frontend/src/conversation/ConversationBubble.tsx b/frontend/src/conversation/ConversationBubble.tsx index 0b7498d2..c92cf870 100644 --- a/frontend/src/conversation/ConversationBubble.tsx +++ b/frontend/src/conversation/ConversationBubble.tsx @@ -403,6 +403,15 @@ const ConversationBubble = forwardRef< const match = /language-(\w+)/.exec(className || ''); const language = match ? match[1] : ''; + if (language === 'mermaid') { + return ( + + ); + } + return match ? (
@@ -792,15 +801,6 @@ function Thought({ const match = /language-(\w+)/.exec(className || ''); const language = match ? match[1] : ''; - if (language === 'mermaid') { - return ( - - ); - } - return match ? (
From fc0060662b4b67b83ca7424d78ceea544cdc4a35 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Fri, 25 Apr 2025 21:18:49 +0530 Subject: [PATCH 05/26] (fix:mermaid) suppress mermaid injected errors in DOM --- frontend/src/components/MermaidRenderer.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/MermaidRenderer.tsx b/frontend/src/components/MermaidRenderer.tsx index c32b253b..e4f97b19 100644 --- a/frontend/src/components/MermaidRenderer.tsx +++ b/frontend/src/components/MermaidRenderer.tsx @@ -24,6 +24,7 @@ const MermaidRenderer: React.FC = ({ startOnLoad: false, theme: isDarkTheme ? 'dark' : 'default', securityLevel: 'loose', + suppressErrorRendering: true }); const renderDiagram = async (): Promise => { try { @@ -32,10 +33,12 @@ const MermaidRenderer: React.FC = ({ // Render the diagram const { svg } = await mermaid.render(id, code); + if (containerRef.current) { + containerRef.current.innerHTML = svg; + } setSvgContent(svg); setError(null); } catch (err) { - console.error('Mermaid rendering error:', err); setError( `Failed to render Mermaid diagram: ${err instanceof Error ? err.message : String(err)}`, ); @@ -272,7 +275,6 @@ const MermaidRenderer: React.FC = ({ className={`p-4 bg-white dark:bg-eerie-black flex justify-center items-center ${ showCode ? 'md:w-1/2' : 'w-full' }`} - dangerouslySetInnerHTML={{ __html: svgContent }} /> {/* Show the code when button is clicked */} From 545376740cb40b1ca4f68d94b71c3463252c248e Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Sat, 26 Apr 2025 19:33:24 +0530 Subject: [PATCH 06/26] (fix:re-render) useRef to check for bottom --- frontend/src/conversation/ConversationMessages.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/frontend/src/conversation/ConversationMessages.tsx b/frontend/src/conversation/ConversationMessages.tsx index d1a9a24e..941b9682 100644 --- a/frontend/src/conversation/ConversationMessages.tsx +++ b/frontend/src/conversation/ConversationMessages.tsx @@ -38,9 +38,9 @@ export default function ConversationMessages({ const { t } = useTranslation(); const conversationRef = useRef(null); - const [hasScrolledToLast, setHasScrolledToLast] = useState(true); + const atLast = useRef(true); const [eventInterrupt, setEventInterrupt] = useState(false); - + const handleUserInterruption = () => { if (!eventInterrupt && status === 'loading') { setEventInterrupt(true); @@ -64,7 +64,8 @@ export default function ConversationMessages({ const el = conversationRef.current; if (!el) return; const isBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 10; - setHasScrolledToLast(isBottom); + + atLast.current = isBottom }; useEffect(() => { @@ -145,7 +146,7 @@ export default function ConversationMessages({ onTouchMove={handleUserInterruption} className="flex justify-center w-full overflow-y-auto h-full sm:pt-12" > - {queries.length > 0 && !hasScrolledToLast && ( + {queries.length > 0 && !atLast.current && (
); -} +} \ No newline at end of file From 545353dabf9e9b255af86b4f40854e4c3ffd2d5e Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Sun, 27 Apr 2025 03:42:28 +0530 Subject: [PATCH 07/26] (feat:mermaid) use contentLoaded to render --- frontend/src/components/MermaidRenderer.tsx | 44 +++++++++++---------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/frontend/src/components/MermaidRenderer.tsx b/frontend/src/components/MermaidRenderer.tsx index e4f97b19..eefe2e83 100644 --- a/frontend/src/components/MermaidRenderer.tsx +++ b/frontend/src/components/MermaidRenderer.tsx @@ -9,7 +9,7 @@ const MermaidRenderer: React.FC = ({ code, isDarkTheme, }) => { - const containerRef = useRef(null); + const diagramId = useRef(`mermaid-${crypto.randomUUID()}`); const status = useSelector(selectStatus); const [svgContent, setSvgContent] = useState(''); const [error, setError] = useState(null); @@ -19,28 +19,31 @@ const MermaidRenderer: React.FC = ({ useEffect(() => { if (status === 'loading' || !code) return; - // Initialize mermaid with the current theme + mermaid.initialize({ - startOnLoad: false, + startOnLoad: true, theme: isDarkTheme ? 'dark' : 'default', securityLevel: 'loose', suppressErrorRendering: true }); + const renderDiagram = async (): Promise => { try { - // Generate unique ID - const id = `mermaid-${crypto.randomUUID()}`; - - // Render the diagram - const { svg } = await mermaid.render(id, code); - if (containerRef.current) { - containerRef.current.innerHTML = svg; + const element = document.getElementById(diagramId.current); + if (element) { + element.removeAttribute('data-processed'); + element.innerHTML = code; + mermaid.contentLoaded(); + + const svgElement = element.querySelector('svg'); + if (svgElement) { + setSvgContent(svgElement.outerHTML); + } + setError(null); } - setSvgContent(svg); - setError(null); } catch (err) { setError( - `Failed to render Mermaid diagram: ${err instanceof Error ? err.message : String(err)}`, + `Failed to render Mermaid diagram: ${err instanceof Error ? err.message : String(err)}` ); setSvgContent(''); } @@ -269,15 +272,14 @@ const MermaidRenderer: React.FC = ({
) : (
- {/* Show the diagram */} -
+
+
+ {code} +
+
- {/* Show the code when button is clicked */} {showCode && (
               {code}

From 7e28e562d09cb89636495136baa24f8e775cf30d Mon Sep 17 00:00:00 2001
From: ManishMadan2882 
Date: Thu, 1 May 2025 19:37:03 +0530
Subject: [PATCH 08/26] (fix:mermaid) download svg/png

---
 frontend/src/components/MermaidRenderer.tsx | 151 ++++++++++----------
 1 file changed, 74 insertions(+), 77 deletions(-)

diff --git a/frontend/src/components/MermaidRenderer.tsx b/frontend/src/components/MermaidRenderer.tsx
index eefe2e83..bd1e5b03 100644
--- a/frontend/src/components/MermaidRenderer.tsx
+++ b/frontend/src/components/MermaidRenderer.tsx
@@ -68,40 +68,35 @@ const MermaidRenderer: React.FC = ({
     };
   }, [showDownloadMenu]);
 
-  // Function to download as SVG
   const downloadSvg = (): void => {
-    if (!svgContent) return;
-
-    // Add XML declaration and ensure proper namespaces
-    let enhancedSvg = svgContent;
-    if (!enhancedSvg.includes('xmlns=')) {
-      enhancedSvg = enhancedSvg.replace(
-        '\n${svgString}`], 
+      { type: 'image/svg+xml' }
+    );
+    
+    const url = URL.createObjectURL(svgBlob);
     const link = document.createElement('a');
     link.href = url;
     link.download = 'diagram.svg';
@@ -111,74 +106,76 @@ const MermaidRenderer: React.FC = ({
     URL.revokeObjectURL(url);
   };
 
-  // Function to download as PNG
   const downloadPng = (): void => {
-    if (!svgContent) return;
-
-    // Parse the SVG
-    const parser = new DOMParser();
-    const svgDoc = parser.parseFromString(svgContent, 'image/svg+xml');
-    const svgElement = svgDoc.documentElement;
-
-    // Ensure SVG has dimensions
-    let width = parseInt(svgElement.getAttribute('width') || '0');
-    let height = parseInt(svgElement.getAttribute('height') || '0');
-
-    // If dimensions are missing, try to get from viewBox
+    const element = document.getElementById(diagramId.current);
+    if (!element) return;
+    
+    const svgElement = element.querySelector('svg');
+    if (!svgElement) return;
+    
+    const svgClone = svgElement.cloneNode(true) as SVGElement;
+    
+    if (!svgClone.hasAttribute('xmlns')) {
+      svgClone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
+    }
+    
+    let width = parseInt(svgClone.getAttribute('width') || '0');
+    let height = parseInt(svgClone.getAttribute('height') || '0');
+    
     if (!width || !height) {
-      const viewBox = svgElement.getAttribute('viewBox')?.split(' ') || [];
+      const viewBox = svgClone.getAttribute('viewBox')?.split(' ') || [];
       if (viewBox.length === 4) {
         width = parseInt(viewBox[2]);
         height = parseInt(viewBox[3]);
-        svgElement.setAttribute('width', width.toString());
-        svgElement.setAttribute('height', height.toString());
+        svgClone.setAttribute('width', width.toString());
+        svgClone.setAttribute('height', height.toString());
       } else {
         width = 800;
         height = 600;
-        svgElement.setAttribute('width', width.toString());
-        svgElement.setAttribute('height', height.toString());
+        svgClone.setAttribute('width', width.toString());
+        svgClone.setAttribute('height', height.toString());
       }
     }
-
+    
     const serializer = new XMLSerializer();
-    const svgString = serializer.serializeToString(svgDoc);
-
-    // Create an Image object
+    const svgString = serializer.serializeToString(svgClone);
+    const svgBase64 = btoa(unescape(encodeURIComponent(svgString)));
+    const dataUrl = `data:image/svg+xml;base64,${svgBase64}`;
+    
     const img = new Image();
-
-    img.onload = function (): void {
-      // Create a canvas with proper dimensions
+    img.crossOrigin = 'anonymous';
+    
+    img.onload = function(): void {
       const canvas = document.createElement('canvas');
       canvas.width = width;
       canvas.height = height;
-
+      
       const ctx = canvas.getContext('2d');
       if (!ctx) {
         console.error('Could not get canvas context');
         return;
       }
-
-      // Fill with white background
-      ctx.fillStyle = '#ffffff';
+      
       ctx.fillRect(0, 0, canvas.width, canvas.height);
-
-      // Draw the image
+      
       ctx.drawImage(img, 0, 0, width, height);
-
-      // Convert to PNG and download
-      const pngUrl = canvas.toDataURL('image/png');
-      const link = document.createElement('a');
-      link.download = 'diagram.png';
-      link.href = pngUrl;
-      document.body.appendChild(link);
-      link.click();
-      document.body.removeChild(link);
+      
+      try {
+        const pngUrl = canvas.toDataURL('image/png');
+        const link = document.createElement('a');
+        link.download = 'diagram.png';
+        link.href = pngUrl;
+        document.body.appendChild(link);
+        link.click();
+        document.body.removeChild(link);
+      } catch (e) {
+        console.error('Failed to create PNG:', e);
+        // Fallback to SVG download if PNG fails
+        downloadSvg();
+      }
     };
-
-    // Set the image source to the SVG
-    const svgBlob = new Blob([svgString], { type: 'image/svg+xml' });
-    const url = URL.createObjectURL(svgBlob);
-    img.src = url;
+    
+    img.src = dataUrl;
   };
 
   const downloadMmd = (): void => {
@@ -210,7 +207,7 @@ const MermaidRenderer: React.FC = ({
         
         
- + {showDiagramOptions && (
)} - + {showDiagramOptions && (
- + {status === 'loading' ? (
@@ -279,7 +276,7 @@ const MermaidRenderer: React.FC = ({ {code}
- + {showCode && (
               {code}

From 7e7ce276b28e3b4e0293382e878be390265ee4a7 Mon Sep 17 00:00:00 2001
From: ManishMadan2882 
Date: Fri, 2 May 2025 14:12:24 +0530
Subject: [PATCH 09/26] (fix:mermaid/flicker) separated from  markdown

---
 .../src/conversation/ConversationBubble.tsx   | 242 ++++++++++--------
 1 file changed, 140 insertions(+), 102 deletions(-)

diff --git a/frontend/src/conversation/ConversationBubble.tsx b/frontend/src/conversation/ConversationBubble.tsx
index 75cf2633..0a0d0780 100644
--- a/frontend/src/conversation/ConversationBubble.tsx
+++ b/frontend/src/conversation/ConversationBubble.tsx
@@ -1,6 +1,6 @@
 import 'katex/dist/katex.min.css';
 
-import { forwardRef, useRef, useState } from 'react';
+import { forwardRef, Fragment, useRef, useState } from 'react';
 import { useTranslation } from 'react-i18next';
 import ReactMarkdown from 'react-markdown';
 import { useSelector } from 'react-redux';
@@ -193,6 +193,33 @@ const ConversationBubble = forwardRef<
 
       return inlineProcessedContent;
     };
+    const processMarkdownContent = (content: string) => {
+      const processedContent = preprocessLaTeX(content);
+      
+      const contentSegments: Array<{type: 'text' | 'mermaid', content: string}> = [];
+      
+      let lastIndex = 0;
+      const regex = /```mermaid\n([\s\S]*?)```/g;
+      let match;
+      
+      while ((match = regex.exec(processedContent)) !== null) {
+        const textBefore = processedContent.substring(lastIndex, match.index);
+        if (textBefore) {
+          contentSegments.push({ type: 'text', content: textBefore });
+        }
+        
+        contentSegments.push({ type: 'mermaid', content: match[1].trim() });
+        
+        lastIndex = match.index + match[0].length;
+      }
+      
+      const textAfter = processedContent.substring(lastIndex);
+      if (textAfter) {
+        contentSegments.push({ type: 'text', content: textAfter });
+      }
+      
+      return contentSegments;
+    };
     bubble = (
       
- - ); - } - - return match ? ( -
-
- - {language} - - -
- - {String(children).replace(/\n$/, '')} - -
- ) : ( - - {children} - - ); - }, - ul({ children }) { - return ( -
    - {children} -
- ); - }, - ol({ children }) { - return ( -
    - {children} -
- ); - }, - table({ children }) { - return ( -
- - {children} -
-
- ); - }, - thead({ children }) { - return ( - - {children} - - ); - }, - tr({ children }) { - return ( - - {children} - - ); - }, - th({ children }) { - return {children}; - }, - td({ children }) { - return {children}; - }, - }} - > - {preprocessLaTeX(message)} -
+ {(() => { + const contentSegments = processMarkdownContent(message); + return ( + <> + {contentSegments.map((segment, index) => ( + + {segment.type === 'text' ? ( + +
+ + {language} + + +
+ + {String(children).replace(/\n$/, '')} + +
+ ) : ( + + {children} + + ); + }, + ul({ children }) { + return ( +
    + {children} +
+ ); + }, + ol({ children }) { + return ( +
    + {children} +
+ ); + }, + table({ children }) { + return ( +
+ + {children} +
+
+ ); + }, + thead({ children }) { + return ( + + {children} + + ); + }, + tr({ children }) { + return ( + + {children} + + ); + }, + th({ children }) { + return {children}; + }, + td({ children }) { + return {children}; + }, + }} + > + {segment.content} + + ) : ( +
+ +
+ )} + + ))} + + ); + })()}
)} From 16386a952413e6dc97fe93af47f91ce027dc7274 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Sun, 4 May 2025 19:39:24 +0530 Subject: [PATCH 10/26] (feat:mermaid) zoom on hover --- frontend/src/components/MermaidRenderer.tsx | 187 +++++++++++++----- .../src/conversation/ConversationMessages.tsx | 29 +-- 2 files changed, 152 insertions(+), 64 deletions(-) diff --git a/frontend/src/components/MermaidRenderer.tsx b/frontend/src/components/MermaidRenderer.tsx index bd1e5b03..d2ca1276 100644 --- a/frontend/src/components/MermaidRenderer.tsx +++ b/frontend/src/components/MermaidRenderer.tsx @@ -1,8 +1,8 @@ import React, { useEffect, useRef, useState } from 'react'; import mermaid from 'mermaid'; import CopyButton from './CopyButton'; -import { useSelector } from 'react-redux'; -import { selectStatus } from '../conversation/conversationSlice'; +import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; +import { oneLight, vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism'; import { MermaidRendererProps } from './types'; const MermaidRenderer: React.FC = ({ @@ -10,47 +10,90 @@ const MermaidRenderer: React.FC = ({ isDarkTheme, }) => { const diagramId = useRef(`mermaid-${crypto.randomUUID()}`); - const status = useSelector(selectStatus); + // const status = useSelector(selectStatus); + const [localStatus, setLocalStatus] = useState<'loading' | 'idle'>('loading'); const [svgContent, setSvgContent] = useState(''); const [error, setError] = useState(null); const [showCode, setShowCode] = useState(false); const [showDownloadMenu, setShowDownloadMenu] = useState(false); + const [zoomLevel, setZoomLevel] = useState(1); const downloadMenuRef = useRef(null); + const containerRef = useRef(null); + const [hoverPosition, setHoverPosition] = useState<{ x: number, y: number } | null>(null); + const [isHovering, setIsHovering] = useState(false); + + const handleMouseMove = (event: React.MouseEvent) => { + if (!containerRef.current) return; + + const rect = containerRef.current.getBoundingClientRect(); + const x = (event.clientX - rect.left) / rect.width; + const y = (event.clientY - rect.top) / rect.height; + + setHoverPosition({ x, y }); + }; + + const handleMouseEnter = () => setIsHovering(true); + const handleMouseLeave = () => { + setIsHovering(false); + setHoverPosition(null); + }; + + const getTransformOrigin = () => { + if (!hoverPosition) return 'center center'; + return `${hoverPosition.x * 100}% ${hoverPosition.y * 100}%`; + }; + useEffect(() => { + if (!code) { + setLocalStatus('idle'); + return; + } + setLocalStatus('loading'); + + mermaid.initialize({ + startOnLoad: true, + theme: isDarkTheme ? 'dark' : 'default', + securityLevel: 'loose', + suppressErrorRendering: true, + }); + + const renderDiagram = async (): Promise => { + try { + const element = document.getElementById(diagramId.current); + if (element) { + element.removeAttribute('data-processed'); + element.innerHTML = code; + mermaid.contentLoaded(); + + const svgElement = element.querySelector('svg'); + if (svgElement) { + svgElement.setAttribute('width', '100%'); + svgElement.setAttribute('height', 'auto'); + svgElement.style.maxWidth = '100%'; + svgElement.style.width = '100%'; + + svgElement.removeAttribute('viewBox'); + + setSvgContent(svgElement.outerHTML); + } + setError(null); + setLocalStatus('idle'); + } + } catch (err) { + setError( + `Failed to render Mermaid diagram: ${err instanceof Error ? err.message : String(err)}` + ); + setSvgContent(''); + setLocalStatus('idle'); + } + }; + + renderDiagram(); + + }, [code, isDarkTheme]); useEffect(() => { - if (status === 'loading' || !code) return; - - mermaid.initialize({ - startOnLoad: true, - theme: isDarkTheme ? 'dark' : 'default', - securityLevel: 'loose', - suppressErrorRendering: true - }); - - const renderDiagram = async (): Promise => { - try { - const element = document.getElementById(diagramId.current); - if (element) { - element.removeAttribute('data-processed'); - element.innerHTML = code; - mermaid.contentLoaded(); - - const svgElement = element.querySelector('svg'); - if (svgElement) { - setSvgContent(svgElement.outerHTML); - } - setError(null); - } - } catch (err) { - setError( - `Failed to render Mermaid diagram: ${err instanceof Error ? err.message : String(err)}` - ); - setSvgContent(''); - } - }; - - renderDiagram(); - }, [code, isDarkTheme, status]); + setZoomLevel(1); + }, [code]); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { @@ -68,6 +111,7 @@ const MermaidRenderer: React.FC = ({ }; }, [showDownloadMenu]); + const downloadSvg = (): void => { const element = document.getElementById(diagramId.current); if (!element) return; @@ -189,25 +233,26 @@ const MermaidRenderer: React.FC = ({ document.body.removeChild(link); URL.revokeObjectURL(url); }; - + + const downloadOptions = [ { label: 'Download as SVG', action: downloadSvg }, { label: 'Download as PNG', action: downloadPng }, { label: 'Download as MMD', action: downloadMmd }, ]; - const showDiagramOptions = status !== 'loading' && !error; - const errorRender = status !== 'loading' && error; + const showDiagramOptions = localStatus !== 'loading' && !error; + const errorRender = localStatus !== 'loading' && error; return ( -
+
mermaid
- + {showDiagramOptions && (
- {status === 'loading' ? ( + {localStatus === 'loading' ? (
Loading diagram...
- ) : errorRender ? ( + ) : errorRender ? (
{error}
) : ( -
-
-
+ <> +
+
{code}
{showCode && ( -
-              {code}
-            
+
+
+ + Mermaid Code + +
+ + {code} + +
)} -
+ )}
); diff --git a/frontend/src/conversation/ConversationMessages.tsx b/frontend/src/conversation/ConversationMessages.tsx index 941b9682..50c79394 100644 --- a/frontend/src/conversation/ConversationMessages.tsx +++ b/frontend/src/conversation/ConversationMessages.tsx @@ -1,4 +1,4 @@ -import { Fragment, useEffect, useRef, useState } from 'react'; +import { Fragment, useEffect, useRef, useState, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import ArrowDown from '../assets/arrow-down.svg'; @@ -47,25 +47,30 @@ export default function ConversationMessages({ } }; + // Remove Mermaid tracking code that was here + const scrollIntoView = () => { if (!conversationRef?.current || eventInterrupt) return; - if (status === 'idle' || !queries[queries.length - 1]?.response) { - conversationRef.current.scrollTo({ - behavior: 'smooth', - top: conversationRef.current.scrollHeight, - }); - } else { - conversationRef.current.scrollTop = conversationRef.current.scrollHeight; - } + setTimeout(() => { + if (!conversationRef?.current) return; + + if (status === 'idle' || !queries[queries.length - 1]?.response) { + conversationRef.current.scrollTo({ + behavior: 'smooth', + top: conversationRef.current.scrollHeight, + }); + } else { + conversationRef.current.scrollTop = conversationRef.current.scrollHeight; + } + }, 100); // Small timeout to allow images to render }; const checkScroll = () => { const el = conversationRef.current; if (!el) return; const isBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 10; - - atLast.current = isBottom + atLast.current = isBottom; }; useEffect(() => { @@ -182,4 +187,4 @@ export default function ConversationMessages({
); -} \ No newline at end of file +} From 98856b39acefb26f28f8b855707a638204426e9a Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 6 May 2025 00:53:33 +0530 Subject: [PATCH 11/26] (feat:mermaid) zoom onhover, throw syntax errors --- frontend/src/components/MermaidRenderer.tsx | 46 +++++++++------------ 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/frontend/src/components/MermaidRenderer.tsx b/frontend/src/components/MermaidRenderer.tsx index d2ca1276..ef3e9222 100644 --- a/frontend/src/components/MermaidRenderer.tsx +++ b/frontend/src/components/MermaidRenderer.tsx @@ -4,19 +4,18 @@ import CopyButton from './CopyButton'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { oneLight, vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism'; import { MermaidRendererProps } from './types'; +import { useSelector } from 'react-redux'; +import { selectStatus } from '../conversation/conversationSlice'; const MermaidRenderer: React.FC = ({ code, isDarkTheme, }) => { const diagramId = useRef(`mermaid-${crypto.randomUUID()}`); - // const status = useSelector(selectStatus); - const [localStatus, setLocalStatus] = useState<'loading' | 'idle'>('loading'); - const [svgContent, setSvgContent] = useState(''); + const status = useSelector(selectStatus); const [error, setError] = useState(null); const [showCode, setShowCode] = useState(false); const [showDownloadMenu, setShowDownloadMenu] = useState(false); - const [zoomLevel, setZoomLevel] = useState(1); const downloadMenuRef = useRef(null); const containerRef = useRef(null); const [hoverPosition, setHoverPosition] = useState<{ x: number, y: number } | null>(null); @@ -43,11 +42,7 @@ const MermaidRenderer: React.FC = ({ return `${hoverPosition.x * 100}% ${hoverPosition.y * 100}%`; }; useEffect(() => { - if (!code) { - setLocalStatus('idle'); - return; - } - setLocalStatus('loading'); + if (status === 'loading' || !code) return; mermaid.initialize({ startOnLoad: true, @@ -58,10 +53,11 @@ const MermaidRenderer: React.FC = ({ const renderDiagram = async (): Promise => { try { + await mermaid.parse(code); //throws syntax errors + const element = document.getElementById(diagramId.current); if (element) { element.removeAttribute('data-processed'); - element.innerHTML = code; mermaid.contentLoaded(); const svgElement = element.querySelector('svg'); @@ -73,27 +69,22 @@ const MermaidRenderer: React.FC = ({ svgElement.removeAttribute('viewBox'); - setSvgContent(svgElement.outerHTML); } setError(null); - setLocalStatus('idle'); } } catch (err) { + setError( `Failed to render Mermaid diagram: ${err instanceof Error ? err.message : String(err)}` ); - setSvgContent(''); - setLocalStatus('idle'); } }; renderDiagram(); + }, [code, isDarkTheme]); - useEffect(() => { - setZoomLevel(1); - }, [code]); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { @@ -241,11 +232,13 @@ const MermaidRenderer: React.FC = ({ { label: 'Download as MMD', action: downloadMmd }, ]; - const showDiagramOptions = localStatus !== 'loading' && !error; - const errorRender = localStatus !== 'loading' && error; + const showDiagramOptions = status !== 'loading' && !error; + const errorRender = status !== 'loading' && error; + + return ( -
+
mermaid @@ -300,7 +293,7 @@ const MermaidRenderer: React.FC = ({
- {localStatus === 'loading' ? ( + {status === 'loading' ? (
Loading diagram... @@ -316,22 +309,23 @@ const MermaidRenderer: React.FC = ({ <>
-
= ({ }} > {code} -
+
{showCode && ( From 72e51bb072a0a9daac915f7daf7d27f6ef3f2a2a Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 6 May 2025 04:38:38 +0530 Subject: [PATCH 12/26] (feat:mermaid) dont pass isDarkTheme --- frontend/src/components/MermaidRenderer.tsx | 3 ++- frontend/src/components/types/index.ts | 1 - frontend/src/conversation/ConversationBubble.tsx | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/MermaidRenderer.tsx b/frontend/src/components/MermaidRenderer.tsx index ef3e9222..ac37cfb4 100644 --- a/frontend/src/components/MermaidRenderer.tsx +++ b/frontend/src/components/MermaidRenderer.tsx @@ -6,11 +6,12 @@ import { oneLight, vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/ import { MermaidRendererProps } from './types'; import { useSelector } from 'react-redux'; import { selectStatus } from '../conversation/conversationSlice'; +import { useDarkTheme } from '../hooks'; const MermaidRenderer: React.FC = ({ code, - isDarkTheme, }) => { + const [isDarkTheme] = useDarkTheme(); const diagramId = useRef(`mermaid-${crypto.randomUUID()}`); const status = useSelector(selectStatus); const [error, setError] = useState(null); diff --git a/frontend/src/components/types/index.ts b/frontend/src/components/types/index.ts index 7f8834bb..25dae251 100644 --- a/frontend/src/components/types/index.ts +++ b/frontend/src/components/types/index.ts @@ -26,5 +26,4 @@ export type InputProps = { export type MermaidRendererProps = { code: string; - isDarkTheme: boolean; }; diff --git a/frontend/src/conversation/ConversationBubble.tsx b/frontend/src/conversation/ConversationBubble.tsx index 0a0d0780..67cc1c34 100644 --- a/frontend/src/conversation/ConversationBubble.tsx +++ b/frontend/src/conversation/ConversationBubble.tsx @@ -490,7 +490,6 @@ const ConversationBubble = forwardRef< ) : (
From f37ca95c1012d5918c2e36840877b3ad1415fae2 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 6 May 2025 15:16:14 +0530 Subject: [PATCH 13/26] (fix/mermaid loading): load only the diagrams which stream --- frontend/src/components/MermaidRenderer.tsx | 106 +++++++++--------- frontend/src/components/types/index.ts | 1 + .../src/conversation/ConversationBubble.tsx | 25 +++-- .../src/conversation/ConversationMessages.tsx | 6 +- 4 files changed, 73 insertions(+), 65 deletions(-) diff --git a/frontend/src/components/MermaidRenderer.tsx b/frontend/src/components/MermaidRenderer.tsx index ac37cfb4..b9014581 100644 --- a/frontend/src/components/MermaidRenderer.tsx +++ b/frontend/src/components/MermaidRenderer.tsx @@ -10,6 +10,7 @@ import { useDarkTheme } from '../hooks'; const MermaidRenderer: React.FC = ({ code, + isLoading, }) => { const [isDarkTheme] = useDarkTheme(); const diagramId = useRef(`mermaid-${crypto.randomUUID()}`); @@ -21,70 +22,70 @@ const MermaidRenderer: React.FC = ({ const containerRef = useRef(null); const [hoverPosition, setHoverPosition] = useState<{ x: number, y: number } | null>(null); const [isHovering, setIsHovering] = useState(false); - + const handleMouseMove = (event: React.MouseEvent) => { if (!containerRef.current) return; - + const rect = containerRef.current.getBoundingClientRect(); const x = (event.clientX - rect.left) / rect.width; const y = (event.clientY - rect.top) / rect.height; - + setHoverPosition({ x, y }); }; - + const handleMouseEnter = () => setIsHovering(true); const handleMouseLeave = () => { setIsHovering(false); setHoverPosition(null); }; - + const getTransformOrigin = () => { if (!hoverPosition) return 'center center'; return `${hoverPosition.x * 100}% ${hoverPosition.y * 100}%`; }; useEffect(() => { - if (status === 'loading' || !code) return; - + if ((isLoading !== undefined ? isLoading : status === 'loading') || !code) return; + mermaid.initialize({ startOnLoad: true, theme: isDarkTheme ? 'dark' : 'default', securityLevel: 'loose', suppressErrorRendering: true, }); - + const renderDiagram = async (): Promise => { try { await mermaid.parse(code); //throws syntax errors - + const element = document.getElementById(diagramId.current); if (element) { element.removeAttribute('data-processed'); mermaid.contentLoaded(); - + const svgElement = element.querySelector('svg'); if (svgElement) { svgElement.setAttribute('width', '100%'); svgElement.setAttribute('height', 'auto'); svgElement.style.maxWidth = '100%'; svgElement.style.width = '100%'; - + svgElement.removeAttribute('viewBox'); - + } setError(null); } } catch (err) { - + setError( `Failed to render Mermaid diagram: ${err instanceof Error ? err.message : String(err)}` ); } }; - + renderDiagram(); - - - }, [code, isDarkTheme]); + + + }, [code, isDarkTheme, isLoading]); useEffect(() => { @@ -109,13 +110,13 @@ const MermaidRenderer: React.FC = ({ if (!element) return; const svgElement = element.querySelector('svg'); if (!svgElement) return; - + const svgClone = svgElement.cloneNode(true) as SVGElement; - + if (!svgClone.hasAttribute('xmlns')) { svgClone.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); } - + if (!svgClone.hasAttribute('width') || !svgClone.hasAttribute('height')) { const viewBox = svgClone.getAttribute('viewBox')?.split(' ') || []; if (viewBox.length === 4) { @@ -123,15 +124,15 @@ const MermaidRenderer: React.FC = ({ svgClone.setAttribute('height', viewBox[3]); } } - + const serializer = new XMLSerializer(); const svgString = serializer.serializeToString(svgClone); - + const svgBlob = new Blob( - [`\n${svgString}`], + [`\n${svgString}`], { type: 'image/svg+xml' } ); - + const url = URL.createObjectURL(svgBlob); const link = document.createElement('a'); link.href = url; @@ -145,19 +146,19 @@ const MermaidRenderer: React.FC = ({ const downloadPng = (): void => { const element = document.getElementById(diagramId.current); if (!element) return; - + const svgElement = element.querySelector('svg'); if (!svgElement) return; - + const svgClone = svgElement.cloneNode(true) as SVGElement; - + if (!svgClone.hasAttribute('xmlns')) { svgClone.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); } - + let width = parseInt(svgClone.getAttribute('width') || '0'); let height = parseInt(svgClone.getAttribute('height') || '0'); - + if (!width || !height) { const viewBox = svgClone.getAttribute('viewBox')?.split(' ') || []; if (viewBox.length === 4) { @@ -172,30 +173,30 @@ const MermaidRenderer: React.FC = ({ svgClone.setAttribute('height', height.toString()); } } - + const serializer = new XMLSerializer(); const svgString = serializer.serializeToString(svgClone); const svgBase64 = btoa(unescape(encodeURIComponent(svgString))); const dataUrl = `data:image/svg+xml;base64,${svgBase64}`; - + const img = new Image(); img.crossOrigin = 'anonymous'; - + img.onload = function(): void { const canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; - + const ctx = canvas.getContext('2d'); if (!ctx) { console.error('Could not get canvas context'); return; } - + ctx.fillRect(0, 0, canvas.width, canvas.height); - + ctx.drawImage(img, 0, 0, width, height); - + try { const pngUrl = canvas.toDataURL('image/png'); const link = document.createElement('a'); @@ -210,7 +211,7 @@ const MermaidRenderer: React.FC = ({ downloadSvg(); } }; - + img.src = dataUrl; }; @@ -225,16 +226,17 @@ const MermaidRenderer: React.FC = ({ document.body.removeChild(link); URL.revokeObjectURL(url); }; - - + + const downloadOptions = [ { label: 'Download as SVG', action: downloadSvg }, { label: 'Download as PNG', action: downloadPng }, { label: 'Download as MMD', action: downloadMmd }, ]; - const showDiagramOptions = status !== 'loading' && !error; - const errorRender = status !== 'loading' && error; + const isCurrentlyLoading = isLoading !== undefined ? isLoading : status === 'loading'; + const showDiagramOptions = !isCurrentlyLoading && !error; + const errorRender = !isCurrentlyLoading && error; @@ -246,7 +248,7 @@ const MermaidRenderer: React.FC = ({
- + {showDiagramOptions && (
)} - + {showDiagramOptions && (
- - {status === 'loading' ? ( + + {isCurrentlyLoading ? (
Loading diagram... @@ -308,24 +310,24 @@ const MermaidRenderer: React.FC = ({
) : ( <> -
-
 = ({
               {code}
             
- + {showCode && (
diff --git a/frontend/src/components/types/index.ts b/frontend/src/components/types/index.ts index 25dae251..1c0d138d 100644 --- a/frontend/src/components/types/index.ts +++ b/frontend/src/components/types/index.ts @@ -26,4 +26,5 @@ export type InputProps = { export type MermaidRendererProps = { code: string; + isLoading?: boolean; }; diff --git a/frontend/src/conversation/ConversationBubble.tsx b/frontend/src/conversation/ConversationBubble.tsx index 67cc1c34..5e3b83c1 100644 --- a/frontend/src/conversation/ConversationBubble.tsx +++ b/frontend/src/conversation/ConversationBubble.tsx @@ -53,6 +53,7 @@ const ConversationBubble = forwardRef< toolCalls?: ToolCallsType[]; retryBtn?: React.ReactElement; questionNumber?: number; + isStreaming?: boolean; handleUpdatedQuestionSubmission?: ( updatedquestion?: string, updated?: boolean, @@ -71,6 +72,7 @@ const ConversationBubble = forwardRef< toolCalls, retryBtn, questionNumber, + isStreaming, handleUpdatedQuestionSubmission, }, ref, @@ -195,29 +197,29 @@ const ConversationBubble = forwardRef< }; const processMarkdownContent = (content: string) => { const processedContent = preprocessLaTeX(content); - + const contentSegments: Array<{type: 'text' | 'mermaid', content: string}> = []; - + let lastIndex = 0; const regex = /```mermaid\n([\s\S]*?)```/g; let match; - + while ((match = regex.exec(processedContent)) !== null) { const textBefore = processedContent.substring(lastIndex, match.index); if (textBefore) { contentSegments.push({ type: 'text', content: textBefore }); } - + contentSegments.push({ type: 'mermaid', content: match[1].trim() }); - + lastIndex = match.index + match[0].length; } - + const textAfter = processedContent.substring(lastIndex); if (textAfter) { contentSegments.push({ type: 'text', content: textAfter }); } - + return contentSegments; }; bubble = ( @@ -404,7 +406,7 @@ const ConversationBubble = forwardRef< const { children, className, node, ref, ...rest } = props; const match = /language-(\w+)/.exec(className || ''); const language = match ? match[1] : ''; - + return match ? (
@@ -491,6 +493,7 @@ const ConversationBubble = forwardRef<
)} @@ -505,7 +508,7 @@ const ConversationBubble = forwardRef< {message && (
@@ -513,7 +516,7 @@ const ConversationBubble = forwardRef<
@@ -544,7 +547,7 @@ const ConversationBubble = forwardRef< }`} > (null); const atLast = useRef(true); const [eventInterrupt, setEventInterrupt] = useState(false); - + const handleUserInterruption = () => { if (!eventInterrupt && status === 'loading') { setEventInterrupt(true); @@ -54,7 +54,7 @@ export default function ConversationMessages({ setTimeout(() => { if (!conversationRef?.current) return; - + if (status === 'idle' || !queries[queries.length - 1]?.response) { conversationRef.current.scrollTo({ behavior: 'smooth', @@ -93,6 +93,7 @@ export default function ConversationMessages({ const prepResponseView = (query: Query, index: number) => { let responseView; if (query.thought || query.response) { + const isCurrentlyStreaming = status === 'loading' && index === queries.length - 1; responseView = ( handleFeedback(query, feedback, index) From e56d54c3f0236c4c327e481b481ca44816729198 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 6 May 2025 10:59:25 +0100 Subject: [PATCH 14/26] fix: improve source and description handling in GetAgent and GetAgents responses --- application/api/user/routes.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/application/api/user/routes.py b/application/api/user/routes.py index 3b3cb21f..bacc8bb7 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -997,12 +997,8 @@ class GetAgent(Resource): data = { "id": str(agent["_id"]), "name": agent["name"], - "description": agent["description"], - "source": ( - str(db.dereference(agent["source"])["_id"]) - if "source" in agent and isinstance(agent["source"], DBRef) - else "" - ), + "description": agent.get("description", ""), + "source": (str(source_doc["_id"]) if isinstance(agent.get("source"), DBRef) and (source_doc := db.dereference(agent.get("source"))) else ""), "chunks": agent["chunks"], "retriever": agent.get("retriever", ""), "prompt_id": agent["prompt_id"], @@ -1035,12 +1031,8 @@ class GetAgents(Resource): { "id": str(agent["_id"]), "name": agent["name"], - "description": agent["description"], - "source": ( - str(db.dereference(agent["source"])["_id"]) - if "source" in agent and isinstance(agent["source"], DBRef) - else "" - ), + "description": agent.get("description", ""), + "source": (str(source_doc["_id"]) if isinstance(agent.get("source"), DBRef) and (source_doc := db.dereference(agent.get("source"))) else ""), "chunks": agent["chunks"], "retriever": agent.get("retriever", ""), "prompt_id": agent["prompt_id"], From 7858c48f11fee4865c641200e67425916069cdd5 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 6 May 2025 11:12:26 +0100 Subject: [PATCH 15/26] fix: zip file uploads --- application/api/user/routes.py | 111 ++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 45 deletions(-) diff --git a/application/api/user/routes.py b/application/api/user/routes.py index bacc8bb7..e10082d3 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -439,59 +439,80 @@ class UploadFile(Resource): zip_filename = f"{job_name}.zip" zip_path = f"{base_path}/{zip_filename}" + zip_temp_path = None - def create_zip_archive(temp_paths, **kwargs): + def create_zip_archive(temp_paths, job_name, storage): import tempfile - with tempfile.TemporaryDirectory() as temp_dir: + with tempfile.NamedTemporaryFile(delete=False, suffix=".zip") as temp_zip_file: + zip_output_path = temp_zip_file.name + + with tempfile.TemporaryDirectory() as stage_dir: for path in temp_paths: - file_data = storage.get_file(path) - with open( - os.path.join(temp_dir, os.path.basename(path)), "wb" - ) as f: - f.write(file_data.read()) + try: + file_data = storage.get_file(path) + with open(os.path.join(stage_dir, os.path.basename(path)), "wb") as f: + f.write(file_data.read()) + except Exception as e: + current_app.logger.error(f"Error processing file {path} for zipping: {e}", exc_info=True) + if os.path.exists(zip_output_path): + os.remove(zip_output_path) + raise + try: + shutil.make_archive( + base_name=zip_output_path.replace(".zip", ""), + format="zip", + root_dir=stage_dir, + ) + except Exception as e: + current_app.logger.error(f"Error creating zip archive: {e}", exc_info=True) + if os.path.exists(zip_output_path): + os.remove(zip_output_path) + raise - # Create zip archive - zip_temp = shutil.make_archive( - base_name=os.path.join(temp_dir, job_name), - format="zip", - root_dir=temp_dir, - ) + return zip_output_path - return zip_temp + try: + zip_temp_path = create_zip_archive(temp_files, job_name, storage) + with open(zip_temp_path, "rb") as zip_file: + storage.save_file(zip_file, zip_path) - zip_temp_path = create_zip_archive(temp_files) - with open(zip_temp_path, "rb") as zip_file: - storage.save_file(zip_file, zip_path) + task = ingest.delay( + settings.UPLOAD_FOLDER, + [ + ".rst", + ".md", + ".pdf", + ".txt", + ".docx", + ".csv", + ".epub", + ".html", + ".mdx", + ".json", + ".xlsx", + ".pptx", + ".png", + ".jpg", + ".jpeg", + ], + job_name, + zip_filename, + user, + ) + finally: + # Clean up temporary files + for temp_path in temp_files: + try: + storage.delete_file(temp_path) + except Exception as e: + current_app.logger.error(f"Error deleting temporary file {temp_path}: {e}", exc_info=True) - # Clean up temp files - for temp_path in temp_files: - storage.delete_file(temp_path) + # Clean up the zip file if it was created + if zip_temp_path and os.path.exists(zip_temp_path): + os.remove(zip_temp_path) - task = ingest.delay( - settings.UPLOAD_FOLDER, - [ - ".rst", - ".md", - ".pdf", - ".txt", - ".docx", - ".csv", - ".epub", - ".html", - ".mdx", - ".json", - ".xlsx", - ".pptx", - ".png", - ".jpg", - ".jpeg", - ], - job_name, - zip_filename, - user, - ) - else: + else: # Keep this else block for single file upload # For single file file = files[0] filename = secure_filename(file.filename) @@ -519,7 +540,7 @@ class UploadFile(Resource): ".jpeg", ], job_name, - filename, + filename, # Corrected variable for single-file case user, ) From 23f648f53a54409dee54d2fb4152427f3bddf26f Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Wed, 7 May 2025 02:07:57 +0530 Subject: [PATCH 16/26] (feat/mermaid) zoom as per the requirement --- frontend/src/components/MermaidRenderer.tsx | 110 ++++++++++++++------ 1 file changed, 79 insertions(+), 31 deletions(-) diff --git a/frontend/src/components/MermaidRenderer.tsx b/frontend/src/components/MermaidRenderer.tsx index b9014581..11285bc5 100644 --- a/frontend/src/components/MermaidRenderer.tsx +++ b/frontend/src/components/MermaidRenderer.tsx @@ -22,6 +22,7 @@ const MermaidRenderer: React.FC = ({ const containerRef = useRef(null); const [hoverPosition, setHoverPosition] = useState<{ x: number, y: number } | null>(null); const [isHovering, setIsHovering] = useState(false); + const [zoomFactor, setZoomFactor] = useState(2); const handleMouseMove = (event: React.MouseEvent) => { if (!containerRef.current) return; @@ -39,55 +40,70 @@ const MermaidRenderer: React.FC = ({ setHoverPosition(null); }; + + const handleKeyDown = (event: React.KeyboardEvent) => { + if (!isHovering) return; + + if (event.key === '+' || event.key === '=') { + setZoomFactor(prev => Math.min(6, prev + 0.5)); // Cap at 6x + event.preventDefault(); + } + else if (event.key === '-') { + setZoomFactor(prev => Math.max(1, prev - 0.5)); // Minimum 1x + event.preventDefault(); + } + }; + + const handleWheel = (event: React.WheelEvent) => { + if (!isHovering) return; + + if ( event.ctrlKey || event.metaKey) { + event.preventDefault(); + + if (event.deltaY < 0) { + setZoomFactor(prev => Math.min(6, prev + 0.25)); + } else { + setZoomFactor(prev => Math.max(1, prev - 0.25)); + } + } + }; + const getTransformOrigin = () => { if (!hoverPosition) return 'center center'; return `${hoverPosition.x * 100}% ${hoverPosition.y * 100}%`; }; - useEffect(() => { - if ((isLoading !== undefined ? isLoading : status === 'loading') || !code) return; + useEffect(() => { + const renderDiagram = async () => { mermaid.initialize({ startOnLoad: true, theme: isDarkTheme ? 'dark' : 'default', securityLevel: 'loose', suppressErrorRendering: true, }); - - const renderDiagram = async (): Promise => { + + const isCurrentlyLoading = isLoading !== undefined ? isLoading : status === 'loading'; + if (!isCurrentlyLoading && code) { try { - await mermaid.parse(code); //throws syntax errors - const element = document.getElementById(diagramId.current); if (element) { element.removeAttribute('data-processed'); + await mermaid.parse(code); //syntax check mermaid.contentLoaded(); - - const svgElement = element.querySelector('svg'); - if (svgElement) { - svgElement.setAttribute('width', '100%'); - svgElement.setAttribute('height', 'auto'); - svgElement.style.maxWidth = '100%'; - svgElement.style.width = '100%'; - - svgElement.removeAttribute('viewBox'); - - } - setError(null); } } catch (err) { - - setError( - `Failed to render Mermaid diagram: ${err instanceof Error ? err.message : String(err)}` - ); + console.error('Error rendering mermaid diagram:', err); + setError(`Failed to render diagram: ${err instanceof Error ? err.message : String(err)}`); } - }; - - renderDiagram(); - + } + }; + renderDiagram(); }, [code, isDarkTheme, isLoading]); + + useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( @@ -238,8 +254,6 @@ const MermaidRenderer: React.FC = ({ const showDiagramOptions = !isCurrentlyLoading && !error; const errorRender = !isCurrentlyLoading && error; - - return (
@@ -302,7 +316,7 @@ const MermaidRenderer: React.FC = ({ Loading diagram...
- ) : errorRender ? ( + ) : errorRender ? (
{error} @@ -312,7 +326,7 @@ const MermaidRenderer: React.FC = ({ <>
= ({ onMouseMove={handleMouseMove} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} + onKeyDown={handleKeyDown} + onWheel={handleWheel} + tabIndex={0} + > + {isHovering && ( + <> +
+ + { + setZoomFactor(2); + }} + title="Reset zoom" + > + {zoomFactor.toFixed(1)}x + + +
+ + )}
Date: Wed, 7 May 2025 02:48:49 +0530
Subject: [PATCH 17/26] (fix/scroll) bring back arrowDown button, smoother
 scroll

---
 .../src/conversation/ConversationMessages.tsx     | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/frontend/src/conversation/ConversationMessages.tsx b/frontend/src/conversation/ConversationMessages.tsx
index 0839b88f..52162658 100644
--- a/frontend/src/conversation/ConversationMessages.tsx
+++ b/frontend/src/conversation/ConversationMessages.tsx
@@ -1,4 +1,4 @@
-import { Fragment, useEffect, useRef, useState, useCallback } from 'react';
+import { Fragment, useEffect, useRef, useState } from 'react';
 import { useTranslation } from 'react-i18next';
 
 import ArrowDown from '../assets/arrow-down.svg';
@@ -38,7 +38,7 @@ export default function ConversationMessages({
   const { t } = useTranslation();
 
   const conversationRef = useRef(null);
-  const atLast = useRef(true);
+  const [atLast,setAtLast] = useState(true);
   const [eventInterrupt, setEventInterrupt] = useState(false);
 
   const handleUserInterruption = () => {
@@ -47,12 +47,11 @@ export default function ConversationMessages({
     }
   };
 
-  // Remove Mermaid tracking code that was here
 
   const scrollIntoView = () => {
     if (!conversationRef?.current || eventInterrupt) return;
 
-    setTimeout(() => {
+    requestAnimationFrame(() => {
       if (!conversationRef?.current) return;
 
       if (status === 'idle' || !queries[queries.length - 1]?.response) {
@@ -63,14 +62,14 @@ export default function ConversationMessages({
       } else {
         conversationRef.current.scrollTop = conversationRef.current.scrollHeight;
       }
-    }, 100); // Small timeout to allow images to render
+    });
   };
 
   const checkScroll = () => {
     const el = conversationRef.current;
     if (!el) return;
     const isBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 10;
-    atLast.current = isBottom;
+    setAtLast(isBottom);
   };
 
   useEffect(() => {
@@ -151,9 +150,9 @@ export default function ConversationMessages({
       ref={conversationRef}
       onWheel={handleUserInterruption}
       onTouchMove={handleUserInterruption}
-      className="flex justify-center w-full overflow-y-auto h-full sm:pt-12"
+      className="flex justify-center w-full overflow-y-auto h-full sm:pt-12 will-change-scroll"
     >
-      {queries.length > 0 && !atLast.current && (
+      {queries.length > 0 && !atLast && (
         
diff --git a/frontend/src/PageNotFound.tsx b/frontend/src/PageNotFound.tsx
index 0b86d7c1..4ee3a476 100644
--- a/frontend/src/PageNotFound.tsx
+++ b/frontend/src/PageNotFound.tsx
@@ -6,7 +6,7 @@ export default function PageNotFound() {
       

404

The page you are looking for does not exist.

-

diff --git a/frontend/src/agents/index.tsx b/frontend/src/agents/index.tsx index c2edb34a..d0052111 100644 --- a/frontend/src/agents/index.tsx +++ b/frontend/src/agents/index.tsx @@ -3,7 +3,6 @@ import { useSelector, useDispatch } from 'react-redux'; import { Route, Routes, useNavigate } from 'react-router-dom'; import userService from '../api/services/userService'; -import Copy from '../assets/copy-linear.svg'; import Edit from '../assets/edit.svg'; import Monitoring from '../assets/monitoring.svg'; import Trash from '../assets/red-trash.svg'; diff --git a/frontend/src/components/Accordion.tsx b/frontend/src/components/Accordion.tsx index ec0a81d7..45c3170d 100644 --- a/frontend/src/components/Accordion.tsx +++ b/frontend/src/components/Accordion.tsx @@ -32,9 +32,9 @@ export default function Accordion({ setIsOpen(!isOpen); }; return ( -
+
{rowsPerPageOptions.map((option) => (
handleSelectRowsPerPage(option)} - className={`cursor-pointer px-4 py-2 text-xs hover:bg-gray-100 dark:hover:bg-neutral-700 ${ + className={`cursor-pointer px-4 py-2 text-xs hover:bg-gray-100 dark:hover:bg-neutral-700 ${ rowsPerPage === option ? 'bg-gray-100 dark:bg-neutral-700 dark:text-light-gray' : 'bg-white dark:bg-dark-charcoal dark:text-light-gray' @@ -97,45 +97,45 @@ const Pagination: React.FC = ({
diff --git a/frontend/src/components/DropdownMenu.tsx b/frontend/src/components/DropdownMenu.tsx index 56242d7a..3fe85508 100644 --- a/frontend/src/components/DropdownMenu.tsx +++ b/frontend/src/components/DropdownMenu.tsx @@ -88,7 +88,7 @@ export default function DropdownMenu({ onClick={(e) => e.stopPropagation()} >
{ {isOpen && (
{ Email Us {t('emailUs')} diff --git a/frontend/src/components/MermaidRenderer.tsx b/frontend/src/components/MermaidRenderer.tsx index 06d5628b..bc56f023 100644 --- a/frontend/src/components/MermaidRenderer.tsx +++ b/frontend/src/components/MermaidRenderer.tsx @@ -2,7 +2,10 @@ import React, { useEffect, useRef, useState } from 'react'; import mermaid from 'mermaid'; import CopyButton from './CopyButton'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; -import { oneLight, vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism'; +import { + oneLight, + vscDarkPlus, +} from 'react-syntax-highlighter/dist/cjs/styles/prism'; import { MermaidRendererProps } from './types'; import { useSelector } from 'react-redux'; import { selectStatus } from '../conversation/conversationSlice'; @@ -20,9 +23,12 @@ const MermaidRenderer: React.FC = ({ const [showDownloadMenu, setShowDownloadMenu] = useState(false); const downloadMenuRef = useRef(null); const containerRef = useRef(null); - const [hoverPosition, setHoverPosition] = useState<{ x: number, y: number } | null>(null); + const [hoverPosition, setHoverPosition] = useState<{ + x: number; + y: number; + } | null>(null); const [isHovering, setIsHovering] = useState(false); - const [zoomFactor, setZoomFactor] = useState(2); + const [zoomFactor, setZoomFactor] = useState(2); const handleMouseMove = (event: React.MouseEvent) => { if (!containerRef.current) return; @@ -40,16 +46,14 @@ const MermaidRenderer: React.FC = ({ setHoverPosition(null); }; - const handleKeyDown = (event: React.KeyboardEvent) => { if (!isHovering) return; if (event.key === '+' || event.key === '=') { - setZoomFactor(prev => Math.min(6, prev + 0.5)); // Cap at 6x + setZoomFactor((prev) => Math.min(6, prev + 0.5)); // Cap at 6x event.preventDefault(); - } - else if (event.key === '-') { - setZoomFactor(prev => Math.max(1, prev - 0.5)); // Minimum 1x + } else if (event.key === '-') { + setZoomFactor((prev) => Math.max(1, prev - 0.5)); // Minimum 1x event.preventDefault(); } }; @@ -57,13 +61,13 @@ const MermaidRenderer: React.FC = ({ const handleWheel = (event: React.WheelEvent) => { if (!isHovering) return; - if ( event.ctrlKey || event.metaKey) { + if (event.ctrlKey || event.metaKey) { event.preventDefault(); if (event.deltaY < 0) { - setZoomFactor(prev => Math.min(6, prev + 0.25)); + setZoomFactor((prev) => Math.min(6, prev + 0.25)); } else { - setZoomFactor(prev => Math.max(1, prev - 0.25)); + setZoomFactor((prev) => Math.max(1, prev - 0.25)); } } }; @@ -81,8 +85,9 @@ const MermaidRenderer: React.FC = ({ securityLevel: 'loose', suppressErrorRendering: true, }); - - const isCurrentlyLoading = isLoading !== undefined ? isLoading : status === 'loading'; + + const isCurrentlyLoading = + isLoading !== undefined ? isLoading : status === 'loading'; if (!isCurrentlyLoading && code) { try { const element = document.getElementById(diagramId.current); @@ -93,7 +98,9 @@ const MermaidRenderer: React.FC = ({ } } catch (err) { console.error('Error rendering mermaid diagram:', err); - setError(`Failed to render diagram: ${err instanceof Error ? err.message : String(err)}`); + setError( + `Failed to render diagram: ${err instanceof Error ? err.message : String(err)}`, + ); } } }; @@ -101,9 +108,6 @@ const MermaidRenderer: React.FC = ({ renderDiagram(); }, [code, isDarkTheme, isLoading]); - - - useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( @@ -120,7 +124,6 @@ const MermaidRenderer: React.FC = ({ }; }, [showDownloadMenu]); - const downloadSvg = (): void => { const element = document.getElementById(diagramId.current); if (!element) return; @@ -146,7 +149,7 @@ const MermaidRenderer: React.FC = ({ const svgBlob = new Blob( [`\n${svgString}`], - { type: 'image/svg+xml' } + { type: 'image/svg+xml' }, ); const url = URL.createObjectURL(svgBlob); @@ -198,7 +201,7 @@ const MermaidRenderer: React.FC = ({ const img = new Image(); img.crossOrigin = 'anonymous'; - img.onload = function(): void { + img.onload = function (): void { const canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; @@ -243,20 +246,20 @@ const MermaidRenderer: React.FC = ({ URL.revokeObjectURL(url); }; - const downloadOptions = [ { label: 'Download as SVG', action: downloadSvg }, { label: 'Download as PNG', action: downloadPng }, { label: 'Download as MMD', action: downloadMmd }, ]; - const isCurrentlyLoading = isLoading !== undefined ? isLoading : status === 'loading'; + const isCurrentlyLoading = + isLoading !== undefined ? isLoading : status === 'loading'; const showDiagramOptions = !isCurrentlyLoading && !error; const errorRender = !isCurrentlyLoading && error; return ( -
-
+
+
mermaid @@ -267,13 +270,13 @@ const MermaidRenderer: React.FC = ({
{showDownloadMenu && ( -
+
    {downloadOptions.map((option, index) => (
  • @@ -282,7 +285,7 @@ const MermaidRenderer: React.FC = ({ option.action(); setShowDownloadMenu(false); }} - className="text-xs px-4 py-2 w-full text-left hover:bg-gray-100 dark:hover:bg-gray-700" + className="w-full px-4 py-2 text-left text-xs hover:bg-gray-100 dark:hover:bg-gray-700" > {option.label} @@ -297,7 +300,7 @@ const MermaidRenderer: React.FC = ({ {showDiagramOptions && (
{isCurrentlyLoading ? ( -
+
Loading diagram...
) : errorRender ? ( -
-
+
+
{error}
@@ -326,13 +329,12 @@ const MermaidRenderer: React.FC = ({ <>
= ({ onKeyDown={handleKeyDown} onWheel={handleWheel} tabIndex={0} - > {isHovering && ( <> -
- - { - setZoomFactor(2); - }} - title="Reset zoom" - > - {zoomFactor.toFixed(1)}x - - -
+
+ + { + setZoomFactor(2); + }} + title="Reset zoom" + > + {zoomFactor.toFixed(1)}x + + +
)}
 = ({
                 cursor: 'default',
                 width: '100%',
                 display: 'flex',
-                justifyContent: 'center'
+                justifyContent: 'center',
               }}
             >
               {code}
@@ -391,7 +396,7 @@ const MermaidRenderer: React.FC = ({
 
           {showCode && (
             
-
+
Mermaid Code @@ -403,7 +408,7 @@ const MermaidRenderer: React.FC = ({ margin: 0, borderRadius: 0, scrollbarWidth: 'thin', - maxHeight: '300px' + maxHeight: '300px', }} > {code} diff --git a/frontend/src/components/ShareButton.tsx b/frontend/src/components/ShareButton.tsx index 8d4a93de..e912ea22 100644 --- a/frontend/src/components/ShareButton.tsx +++ b/frontend/src/components/ShareButton.tsx @@ -15,7 +15,7 @@ export default function ShareButton({ conversationId }: ShareButtonProps) { onClick={() => { setShareModalState(true); }} - className="absolute top-4 right-20 z-20 rounded-full hover:bg-bright-gray dark:hover:bg-[#28292E]" + className="absolute right-20 top-4 z-20 rounded-full hover:bg-bright-gray dark:hover:bg-[#28292E]" >
-
+
{children}
diff --git a/frontend/src/components/SkeletonLoader.tsx b/frontend/src/components/SkeletonLoader.tsx index 2433110a..71b796d8 100644 --- a/frontend/src/components/SkeletonLoader.tsx +++ b/frontend/src/components/SkeletonLoader.tsx @@ -42,17 +42,17 @@ const SkeletonLoader: React.FC = ({ <> {[...Array(4)].map((_, idx) => ( - -
+ +
- -
+ +
- -
+ +
- -
+ +
))} @@ -64,16 +64,16 @@ const SkeletonLoader: React.FC = ({ {[...Array(4)].map((_, idx) => ( -
+
-
+
-
+
-
+
))} @@ -82,10 +82,10 @@ const SkeletonLoader: React.FC = ({ const renderDropdown = () => (
-
-
-
-
+
+
+
+
); @@ -95,14 +95,14 @@ const SkeletonLoader: React.FC = ({ {[...Array(8)].map((_, idx) => (
-
-
-
-
-
-
+
+
+
+
+
+
@@ -117,32 +117,32 @@ const SkeletonLoader: React.FC = ({ key={idx} className={`p-6 ${ skeletonCount === 1 ? 'w-full' : 'w-60' - } dark:bg-raisin-black rounded-3xl animate-pulse`} + } animate-pulse rounded-3xl dark:bg-raisin-black`} >
-
-
-
-
-
+
+
+
+
+
-
+
-
-
-
+
+
+
-
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
))} @@ -154,27 +154,27 @@ const SkeletonLoader: React.FC = ({ {[...Array(skeletonCount)].map((_, idx) => (
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
diff --git a/frontend/src/components/SourcesPopup.tsx b/frontend/src/components/SourcesPopup.tsx index 088b3eb1..6846cf84 100644 --- a/frontend/src/components/SourcesPopup.tsx +++ b/frontend/src/components/SourcesPopup.tsx @@ -32,8 +32,13 @@ export default function SourcesPopup({ const { t } = useTranslation(); const popupRef = useRef(null); const [searchTerm, setSearchTerm] = useState(''); - const [popupPosition, setPopupPosition] = useState({ top: 0, left: 0, maxHeight: 0, showAbove: false }); - + const [popupPosition, setPopupPosition] = useState({ + top: 0, + left: 0, + maxHeight: 0, + showAbove: false, + }); + const embeddingsName = import.meta.env.VITE_EMBEDDINGS_NAME || 'huggingface_sentence-transformers/all-mpnet-base-v2'; @@ -41,16 +46,16 @@ export default function SourcesPopup({ const options = useSelector(selectSourceDocs); const selectedDocs = useSelector(selectSelectedDocs); - const filteredOptions = options?.filter(option => - option.name.toLowerCase().includes(searchTerm.toLowerCase()) + const filteredOptions = options?.filter((option) => + option.name.toLowerCase().includes(searchTerm.toLowerCase()), ); useLayoutEffect(() => { if (!isOpen || !anchorRef.current) return; - + const updatePosition = () => { if (!anchorRef.current) return; - + const rect = anchorRef.current.getBoundingClientRect(); const viewportHeight = window.innerHeight; const viewportWidth = window.innerWidth; @@ -60,17 +65,17 @@ export default function SourcesPopup({ const maxHeight = showAbove ? spaceAbove - 16 : spaceBelow - 16; const left = Math.min( rect.left, - viewportWidth - Math.min(480, viewportWidth * 0.95) - 10 + viewportWidth - Math.min(480, viewportWidth * 0.95) - 10, ); - + setPopupPosition({ top: showAbove ? rect.top - 8 : rect.bottom + 8, left, maxHeight: Math.min(600, maxHeight), - showAbove + showAbove, }); }; - + updatePosition(); window.addEventListener('resize', updatePosition); return () => window.removeEventListener('resize', updatePosition); @@ -111,10 +116,12 @@ export default function SourcesPopup({ return (
-
-
-

+
+
+

{t('conversation.sources.text')}

- +
-
+
{options ? ( <> {filteredOptions?.map((option: any, index: number) => { @@ -149,7 +156,7 @@ export default function SourcesPopup({ return (
{ dispatch(setSelectedDocs(option)); handlePostDocumentSelect(option); @@ -159,23 +166,26 @@ export default function SourcesPopup({ Source - + {option.name} -
- {selectedDocs && - (option.id ? - selectedDocs.id === option.id : // For documents with MongoDB IDs - selectedDocs.date === option.date) && // For preloaded sources - Selected - } +
+ {selectedDocs && + (option.id + ? selectedDocs.id === option.id // For documents with MongoDB IDs + : selectedDocs.date === option.date) && ( // For preloaded sources + Selected + )}
); @@ -183,14 +193,22 @@ export default function SourcesPopup({ return null; })}
- Source - + Source + {t('none')} -
+
{selectedDocs === null && ( Selected )} @@ -198,27 +216,27 @@ export default function SourcesPopup({
) : ( -
+
{t('noSourcesAvailable')}
)}
- -
+
diff --git a/frontend/src/components/ToggleSwitch.tsx b/frontend/src/components/ToggleSwitch.tsx index 3a4ed7db..69530e79 100644 --- a/frontend/src/components/ToggleSwitch.tsx +++ b/frontend/src/components/ToggleSwitch.tsx @@ -46,9 +46,9 @@ const ToggleSwitch: React.FC = ({ return (
diff --git a/frontend/src/components/ToolsPopup.tsx b/frontend/src/components/ToolsPopup.tsx index f0466e95..5fdd6c23 100644 --- a/frontend/src/components/ToolsPopup.tsx +++ b/frontend/src/components/ToolsPopup.tsx @@ -29,18 +29,23 @@ export default function ToolsPopup({ const [searchTerm, setSearchTerm] = useState(''); const [isDarkTheme] = useDarkTheme(); const popupRef = useRef(null); - const [popupPosition, setPopupPosition] = useState({ top: 0, left: 0, maxHeight: 0, showAbove: false }); + const [popupPosition, setPopupPosition] = useState({ + top: 0, + left: 0, + maxHeight: 0, + showAbove: false, + }); useLayoutEffect(() => { if (!isOpen || !anchorRef.current) return; - + const updatePosition = () => { if (!anchorRef.current) return; - + const rect = anchorRef.current.getBoundingClientRect(); const viewportHeight = window.innerHeight; const viewportWidth = window.innerWidth; - + const spaceAbove = rect.top; const spaceBelow = viewportHeight - rect.bottom; const showAbove = spaceAbove > spaceBelow && spaceAbove >= 300; @@ -48,17 +53,17 @@ export default function ToolsPopup({ const left = Math.min( rect.left, - viewportWidth - Math.min(462, viewportWidth * 0.95) - 10 + viewportWidth - Math.min(462, viewportWidth * 0.95) - 10, ); - + setPopupPosition({ top: showAbove ? rect.top - 8 : rect.bottom + 8, left, maxHeight: Math.min(600, maxHeight), - showAbove + showAbove, }); }; - + updatePosition(); window.addEventListener('resize', updatePosition); return () => window.removeEventListener('resize', updatePosition); @@ -125,16 +130,18 @@ export default function ToolsPopup({ if (!isOpen) return null; const filteredTools = userTools.filter((tool) => - tool.displayName.toLowerCase().includes(searchTerm.toLowerCase()) + tool.displayName.toLowerCase().includes(searchTerm.toLowerCase()), ); return (
-
-
-

+
+
+

{t('settings.tools.label')}

@@ -162,20 +169,20 @@ export default function ToolsPopup({
{loading ? ( -
-
+
+
) : ( -
+
{filteredTools.length === 0 ? ( -
+
No tools found -

+

{t('settings.tools.noToolsFound')}

@@ -184,22 +191,24 @@ export default function ToolsPopup({
updateToolStatus(tool.id, !tool.status)} - className="flex items-center justify-between p-3 border-b border-[#D9D9D9] dark:border-dim-gray hover:bg-gray-100 dark:hover:bg-charleston-green-3" + className="flex items-center justify-between border-b border-[#D9D9D9] p-3 hover:bg-gray-100 dark:border-dim-gray dark:hover:bg-charleston-green-3" > -
+
{`${tool.displayName}
-

+

{tool.displayName}

-
-
+
+
{tool.status && ( )} -
+
{t('settings.tools.manageTools')} + } /> {!isEditClicked && ( <> -
+
{message}
@@ -128,7 +134,7 @@ const ConversationBubble = forwardRef< setIsEditClicked(true); setEditInputBox(message ?? ''); }} - className={`flex-shrink-0 h-fit mt-3 p-2 cursor-pointer rounded-full hover:bg-light-silver dark:hover:bg-[#35363B] flex items-center ${isQuestionHovered || isEditClicked ? 'visible' : 'invisible'}`} + className={`mt-3 flex h-fit flex-shrink-0 cursor-pointer items-center rounded-full p-2 hover:bg-light-silver dark:hover:bg-[#35363B] ${isQuestionHovered || isEditClicked ? 'visible' : 'invisible'}`} > Edit @@ -137,7 +143,7 @@ const ConversationBubble = forwardRef< {isEditClicked && (
-
+
-
-
+
+
- - - - @@ -151,7 +151,7 @@ export default function APIKeys() { @@ -163,22 +163,22 @@ export default function APIKeys() { key={element.id} className="group transition-colors hover:bg-gray-50 dark:hover:bg-gray-800/50" > - - - -
+ {t('settings.apiKeys.name')} + {t('settings.apiKeys.sourceDoc')} + {t('settings.apiKeys.key')} @@ -139,7 +139,7 @@ export default function APIKeys() { {t('settings.apiKeys.key')} + Actions
{t('settings.apiKeys.noData')} +
{element.name}
+
{element.source}
+
{element.key}
+
-
-
+
+
- - - - @@ -370,7 +370,7 @@ export default function Documents({ @@ -382,26 +382,26 @@ export default function Documents({ return ( - - @@ -824,20 +824,20 @@ function APIActionTable({ } }} placeholder="New property key" - className="min-w-[130.5px] w-full flex items-start bg-transparent border border-silver dark:border-silver/40 outline-none px-2 py-1 rounded-lg text-sm" + className="flex w-full min-w-[130.5px] items-start rounded-lg border border-silver bg-transparent px-2 py-1 text-sm outline-none dark:border-silver/40" />
+ {t('settings.documents.name')} -
+
+
{t('settings.documents.date')} refreshDocs('date')} src={caretSort} alt="sort" />
-
+
+
{t('settings.documents.tokenUsage')} @@ -351,14 +351,14 @@ export default function Documents({ {t('settings.documents.tokenUsage')} refreshDocs('tokens')} src={caretSort} alt="sort" />
+ {t('settings.documents.actions')}
{t('settings.documents.noData')}
{document.name} + {document.date ? formatDate(document.date) : ''} + {document.tokens ? formatTokens(+document.tokens) : ''} e.stopPropagation()} >
{document.syncFrequency && ( handleMenuClick(e, docId)} - className="inline-flex items-center justify-center w-8 h-8 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors flex-shrink-0" + className="inline-flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full transition-colors hover:bg-gray-100 dark:hover:bg-gray-700" aria-label="Open menu" data-testid={`menu-button-${docId}`} > @@ -633,19 +633,19 @@ function DocumentChunks({ fetchChunks(); }, [page, perPage]); return ( -
-
+
+

Back to all documents

-
-
-

{`${totalChunks} Chunks`}

+
+
+

{`${totalChunks} Chunks`}

@@ -663,7 +663,7 @@ function DocumentChunks({ />
{loading ? ( -
-
+
+
) : ( -
+
{paginatedChunks.filter((chunk) => { if (!chunk.metadata?.title) return true; return chunk.metadata.title .toLowerCase() .includes(searchTerm.toLowerCase()); }).length === 0 ? ( -
+
No tools found No chunks found
@@ -703,10 +703,10 @@ function DocumentChunks({ .map((chunk, index) => (
-
+
-

+

{chunk.metadata?.title ?? 'Untitled'}

-

+

{chunk.text}

@@ -745,7 +745,7 @@ function DocumentChunks({ .toLowerCase() .includes(searchTerm.toLowerCase()); }).length !== 0 && ( -
+
{' '} -
-
-
-
-
+

Back to all tools

@@ -128,7 +128,7 @@ export default function ToolConfig({

Type

-

+

{tool.name}

@@ -138,7 +138,7 @@ export default function ToolConfig({ Authentication

)} -
+
{Object.keys(tool?.config).length !== 0 && tool.name !== 'api_tool' && (
@@ -153,13 +153,13 @@ export default function ToolConfig({ )}
-
-
+
+

Actions

@@ -177,7 +177,7 @@ export default function ToolConfig({ onClick={() => { setActionModalState('ACTIVE'); }} - className="border border-solid border-violets-are-blue text-violets-are-blue transition-colors hover:bg-violets-are-blue hover:text-white rounded-full text-sm px-5 py-1" + className="rounded-full border border-solid border-violets-are-blue px-5 py-1 text-sm text-violets-are-blue transition-colors hover:bg-violets-are-blue hover:text-white" > Add action @@ -191,9 +191,9 @@ export default function ToolConfig({ return (
-
+

{action.name}

@@ -214,10 +214,10 @@ export default function ToolConfig({ id={`actionToggle-${actionIndex}`} />
-
+
{ @@ -285,7 +285,7 @@ export default function ToolConfig({ { setTool({ ...tool, @@ -321,7 +321,7 @@ export default function ToolConfig({ value={param[1].value} key={uniqueKey} disabled={param[1].filled_by_llm} - className={`bg-transparent border border-silver dark:border-silver/40 outline-none px-2 py-1 rounded-lg text-sm ${param[1].filled_by_llm ? 'opacity-50' : ''}`} + className={`rounded-lg border border-silver bg-transparent px-2 py-1 text-sm outline-none dark:border-silver/40 ${param[1].filled_by_llm ? 'opacity-50' : ''}`} onChange={(e) => { setTool({ ...tool, @@ -424,9 +424,9 @@ function APIToolConfig({ return (
-
+

{action.name}

@@ -439,7 +439,7 @@ function APIToolConfig({
- + URL
- + Method
- + Description setNewPropertyKey(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') { @@ -724,26 +724,26 @@ function APIActionTable({
) : ( handleRenamePropertyStart(section, key)} readOnly /> @@ -772,7 +772,7 @@ function APIActionTable({
handlePropertyChange( section, @@ -790,7 +790,7 @@ function APIActionTable({ onChange={(e) => handlePropertyChange(section, key, 'value', e.target.value) } - className={`bg-transparent border border-silver dark:border-silver/40 outline-none px-2 py-1 rounded-lg text-sm ${param.filled_by_llm ? 'opacity-50' : ''}`} + className={`rounded-lg border border-silver bg-transparent px-2 py-1 text-sm outline-none dark:border-silver/40 ${param.filled_by_llm ? 'opacity-50' : ''}`} >
diff --git a/frontend/src/settings/Tools.tsx b/frontend/src/settings/Tools.tsx index 3a91d30f..9c7b6906 100644 --- a/frontend/src/settings/Tools.tsx +++ b/frontend/src/settings/Tools.tsx @@ -101,8 +101,8 @@ export default function Tools() { /> ) : (
-
-
+
+
-
+
{loading ? ( -
-
+
+
) : ( -
+
{userTools.length === 0 ? ( -
+
No tools found -

+

{t('settings.tools.noToolsFound')}

@@ -157,14 +157,14 @@ export default function Tools() { .map((tool, index) => (
-
+
{`${tool.displayName}

{tool.displayName}

-

+

{tool.description}

diff --git a/frontend/src/upload/Upload.tsx b/frontend/src/upload/Upload.tsx index 8c016b29..61a7bc47 100644 --- a/frontend/src/upload/Upload.tsx +++ b/frontend/src/upload/Upload.tsx @@ -69,8 +69,8 @@ function Upload({ : 'grid-rows-[0fr] opacity-0' }`} > -
-
+
+
{advancedFields.map((field: FormField) => renderField(field))}
@@ -212,11 +212,11 @@ function Upload({ function ProgressBar({ progressPercent }: { progressPercent: number }) { return ( -
-
+
+
{t('modals.uploadDoc.start')} ) : ( @@ -617,7 +617,7 @@ function Upload({ required={true} />
- + {t('modals.uploadDoc.choose')} @@ -633,7 +633,7 @@ function Upload({ {files.map((file) => (

{file.name} @@ -681,7 +681,7 @@ function Upload({ ) && ( @@ -709,7 +709,7 @@ function Upload({ } }} disabled={isUploadDisabled()} - className={`rounded-3xl px-4 py-2 font-medium text-[14px] ${ + className={`rounded-3xl px-4 py-2 text-[14px] font-medium ${ isUploadDisabled() ? 'cursor-not-allowed bg-gray-300 text-gray-500' : 'cursor-pointer bg-purple-30 text-white hover:bg-violets-are-blue' From 183251487c0cd19cbc60a07ba6fc648ac2ef6320 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 7 May 2025 23:37:35 +0100 Subject: [PATCH 22/26] lint: remove unused import of 'io' in worker.py --- application/worker.py | 1 - 1 file changed, 1 deletion(-) diff --git a/application/worker.py b/application/worker.py index 2f9e97f3..9829fde9 100755 --- a/application/worker.py +++ b/application/worker.py @@ -1,5 +1,4 @@ import datetime -import io import json import logging import mimetypes From 3243740dd1758ba9090009208becdfd8fe037bdd Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Thu, 8 May 2025 16:10:31 +0530 Subject: [PATCH 23/26] (fix-bubble) inconsistent width with snippets --- frontend/src/conversation/ConversationBubble.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/conversation/ConversationBubble.tsx b/frontend/src/conversation/ConversationBubble.tsx index 1f9ceccc..2f9891b5 100644 --- a/frontend/src/conversation/ConversationBubble.tsx +++ b/frontend/src/conversation/ConversationBubble.tsx @@ -370,7 +370,7 @@ const ConversationBubble = forwardRef< )} {message && ( -

+
Date: Fri, 9 May 2025 02:26:35 +0530 Subject: [PATCH 24/26] (fix:ingestion) store file name as metadata, not path --- application/parser/file/bulk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/parser/file/bulk.py b/application/parser/file/bulk.py index 8201b3f2..da6dc298 100644 --- a/application/parser/file/bulk.py +++ b/application/parser/file/bulk.py @@ -158,7 +158,7 @@ class SimpleDirectoryReader(BaseReader): data = f.read() # Prepare metadata for this file if self.file_metadata is not None: - file_metadata = self.file_metadata(str(input_file)) + file_metadata = self.file_metadata(input_file.name) else: # Provide a default empty metadata file_metadata = {'title': '', 'store': ''} From 7d76a337901239835014ad55c1174fbef8c9738e Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 9 May 2025 22:15:55 +0100 Subject: [PATCH 25/26] fix:(style) update layout for agent list and card components --- frontend/src/agents/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/agents/index.tsx b/frontend/src/agents/index.tsx index d0052111..4634dc76 100644 --- a/frontend/src/agents/index.tsx +++ b/frontend/src/agents/index.tsx @@ -127,7 +127,7 @@ function AgentsList() { New Agent
-
+
{loading ? (
@@ -231,7 +231,7 @@ function AgentCard({ }; return (
{ e.stopPropagation(); handleClick(); From 32803c89a393406926658d8a52f7f7195df46712 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 9 May 2025 22:52:17 +0100 Subject: [PATCH 26/26] fix: truncate tool call results to 50 characters for cleaner output --- application/agents/classic_agent.py | 4 ++++ application/agents/react_agent.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/application/agents/classic_agent.py b/application/agents/classic_agent.py index b96a77fc..b371123b 100644 --- a/application/agents/classic_agent.py +++ b/application/agents/classic_agent.py @@ -57,4 +57,8 @@ class ClassicAgent(BaseAgent): ) yield {"sources": retrieved_data} + # clean tool_call_data only send first 50 characters of tool_call['result'] + for tool_call in self.tool_calls: + if len(str(tool_call["result"])) > 50: + tool_call["result"] = str(tool_call["result"])[:50] + "..." yield {"tool_calls": self.tool_calls.copy()} diff --git a/application/agents/react_agent.py b/application/agents/react_agent.py index a5d47850..5fce00b3 100644 --- a/application/agents/react_agent.py +++ b/application/agents/react_agent.py @@ -87,6 +87,10 @@ class ReActAgent(BaseAgent): ) yield {"sources": retrieved_data} + # clean tool_call_data only send first 50 characters of tool_call['result'] + for tool_call in self.tool_calls: + if len(str(tool_call["result"])) > 50: + tool_call["result"] = str(tool_call["result"])[:50] + "..." yield {"tool_calls": self.tool_calls.copy()} final_answer = self._create_final_answer(query, self.observations, log_context)