From 5ccb131a67a050c328d043484c29654d7a0f20e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Apr 2025 16:43:46 -0700 Subject: [PATCH 001/172] chore(deps-dev): Bump vite from 5.4.17 to 5.4.18 (#11324) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.4.17 to 5.4.18.
Release notes

Sourced from vite's releases.

v5.4.18

Please refer to CHANGELOG.md for details.

Changelog

Sourced from vite's changelog.

5.4.18 (2025-04-10)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=vite&package-manager=npm_and_yarn&previous-version=5.4.17&new-version=5.4.18)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/chatwoot/chatwoot/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 4 +- pnpm-lock.yaml | 248 ++++++++++++++++++++++++------------------------- 2 files changed, 126 insertions(+), 126 deletions(-) diff --git a/package.json b/package.json index c27e12a99..18f4b9268 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "prosemirror-model": "^1.22.3", "size-limit": "^8.2.4", "tailwindcss": "^3.4.13", - "vite": "^5.4.17", + "vite": "^5.4.18", "vite-plugin-ruby": "^5.0.0", "vitest": "3.0.5" }, @@ -154,7 +154,7 @@ "pnpm": { "overrides": { "vite-node": "2.0.1", - "vite": "5.4.17", + "vite": "5.4.18", "vitest": "3.0.5" } }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fd45c7647..73799ff19 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,7 @@ settings: overrides: vite-node: 2.0.1 - vite: 5.4.17 + vite: 5.4.18 vitest: 3.0.5 importers: @@ -72,7 +72,7 @@ importers: version: 8.20.5(vue@3.5.12(typescript@5.6.2)) '@vitejs/plugin-vue': specifier: ^5.1.4 - version: 5.1.4(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2)) + version: 5.1.4(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2)) '@vue/compiler-sfc': specifier: ^3.5.8 version: 3.5.8 @@ -238,7 +238,7 @@ importers: version: 1.8.1(tailwindcss@3.4.13) '@histoire/plugin-vue': specifier: 0.17.15 - version: 0.17.15(histoire@0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)))(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2)) + version: 0.17.15(histoire@0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)))(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2)) '@iconify-json/logos': specifier: ^1.2.3 version: 1.2.3 @@ -301,7 +301,7 @@ importers: version: 6.0.0 histoire: specifier: 0.17.15 - version: 0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) + version: 0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) husky: specifier: ^7.0.0 version: 7.0.4 @@ -330,11 +330,11 @@ importers: specifier: ^3.4.13 version: 3.4.13 vite: - specifier: 5.4.17 - version: 5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) + specifier: 5.4.18 + version: 5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) vite-plugin-ruby: specifier: ^5.0.0 - version: 5.0.0(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) + version: 5.0.0(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) vitest: specifier: 3.0.5 version: 3.0.5(@types/node@22.7.0)(jsdom@24.1.3)(sass@1.79.3)(terser@5.33.0) @@ -860,7 +860,7 @@ packages: '@histoire/shared@0.17.17': resolution: {integrity: sha512-ueGtURysonT0MujCObPCR57+mgZluMEXCrbc2FBgKAD/DoAt38tNwSGsmLldk2O6nTr7lr6ClbVSgWrLwgY6Xw==} peerDependencies: - vite: 5.4.17 + vite: 5.4.18 '@histoire/vendors@0.17.17': resolution: {integrity: sha512-QZvmffdoJlLuYftPIkOU5Q2FPAdG2JjMuQ5jF7NmEl0n1XnmbMqtRkdYTZ4eF6CO1KLZ0Zyf6gBQvoT1uWNcjA==} @@ -1039,103 +1039,103 @@ packages: '@rails/ujs@7.1.400': resolution: {integrity: sha512-YwvXm3BR5tn+VCAKYGycLejMRVZE3Ionj5gFjEeGXCZnI0Rpi+7dKpmyu90kdUY7dRUFpHTdu9zZceEzFLl38w==} - '@rollup/rollup-android-arm-eabi@4.39.0': - resolution: {integrity: sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA==} + '@rollup/rollup-android-arm-eabi@4.40.0': + resolution: {integrity: sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.39.0': - resolution: {integrity: sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==} + '@rollup/rollup-android-arm64@4.40.0': + resolution: {integrity: sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.39.0': - resolution: {integrity: sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q==} + '@rollup/rollup-darwin-arm64@4.40.0': + resolution: {integrity: sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.39.0': - resolution: {integrity: sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==} + '@rollup/rollup-darwin-x64@4.40.0': + resolution: {integrity: sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.39.0': - resolution: {integrity: sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==} + '@rollup/rollup-freebsd-arm64@4.40.0': + resolution: {integrity: sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.39.0': - resolution: {integrity: sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==} + '@rollup/rollup-freebsd-x64@4.40.0': + resolution: {integrity: sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.39.0': - resolution: {integrity: sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==} + '@rollup/rollup-linux-arm-gnueabihf@4.40.0': + resolution: {integrity: sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.39.0': - resolution: {integrity: sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==} + '@rollup/rollup-linux-arm-musleabihf@4.40.0': + resolution: {integrity: sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.39.0': - resolution: {integrity: sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==} + '@rollup/rollup-linux-arm64-gnu@4.40.0': + resolution: {integrity: sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.39.0': - resolution: {integrity: sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==} + '@rollup/rollup-linux-arm64-musl@4.40.0': + resolution: {integrity: sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.39.0': - resolution: {integrity: sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==} + '@rollup/rollup-linux-loongarch64-gnu@4.40.0': + resolution: {integrity: sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.39.0': - resolution: {integrity: sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==} + '@rollup/rollup-linux-powerpc64le-gnu@4.40.0': + resolution: {integrity: sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.39.0': - resolution: {integrity: sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==} + '@rollup/rollup-linux-riscv64-gnu@4.40.0': + resolution: {integrity: sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.39.0': - resolution: {integrity: sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==} + '@rollup/rollup-linux-riscv64-musl@4.40.0': + resolution: {integrity: sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.39.0': - resolution: {integrity: sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==} + '@rollup/rollup-linux-s390x-gnu@4.40.0': + resolution: {integrity: sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.39.0': - resolution: {integrity: sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==} + '@rollup/rollup-linux-x64-gnu@4.40.0': + resolution: {integrity: sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.39.0': - resolution: {integrity: sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==} + '@rollup/rollup-linux-x64-musl@4.40.0': + resolution: {integrity: sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.39.0': - resolution: {integrity: sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==} + '@rollup/rollup-win32-arm64-msvc@4.40.0': + resolution: {integrity: sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.39.0': - resolution: {integrity: sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==} + '@rollup/rollup-win32-ia32-msvc@4.40.0': + resolution: {integrity: sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.39.0': - resolution: {integrity: sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==} + '@rollup/rollup-win32-x64-msvc@4.40.0': + resolution: {integrity: sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==} cpu: [x64] os: [win32] @@ -1800,7 +1800,7 @@ packages: resolution: {integrity: sha512-N2XSI2n3sQqp5w7Y/AN/L2XDjBIRGqXko+eDp42sydYSBeJuSm5a1sLf8zakmo8u7tA8NmBgoDLA1HeOESjp9A==} engines: {node: ^18.0.0 || >=20.0.0} peerDependencies: - vite: 5.4.17 + vite: 5.4.18 vue: ^3.2.25 '@vitest/coverage-v8@3.0.5': @@ -1819,7 +1819,7 @@ packages: resolution: {integrity: sha512-CLPNBFBIE7x6aEGbIjaQAX03ZZlBMaWwAjBdMkIf/cAn6xzLTiM3zYqO/WAbieEjsAZir6tO71mzeHZoodThvw==} peerDependencies: msw: ^2.4.9 - vite: 5.4.17 + vite: 5.4.18 peerDependenciesMeta: msw: optional: true @@ -3100,7 +3100,7 @@ packages: resolution: {integrity: sha512-DiRMSIgj340z+zikqf0f3Pj0CTv2/xtdBMBIAO1EARat+QXxMwumbfK41Gi7f9IIBr+UVmomNcwFxVY2EM/vrw==} hasBin: true peerDependencies: - vite: 5.4.17 + vite: 5.4.18 hotkeys-js@3.8.7: resolution: {integrity: sha512-ckAx3EkUr5XjDwjEHDorHxRO2Kb7z6Z2Sxul4MbBkN8Nho7XDslQsgMJT+CiJ5Z4TgRxxvKHEpuLE3imzqy4Lg==} @@ -4344,8 +4344,8 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rollup@4.39.0: - resolution: {integrity: sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g==} + rollup@4.40.0: + resolution: {integrity: sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -4863,10 +4863,10 @@ packages: vite-plugin-ruby@5.0.0: resolution: {integrity: sha512-c8PjTp21Ah/ttgnNUyu0qvCXZI08Jr9I24oUKg3TRIRhF5GcOZ++6wtlTCrNFd9COEQbpXHxlRIXd/MEg0iZJw==} peerDependencies: - vite: 5.4.17 + vite: 5.4.18 - vite@5.4.17: - resolution: {integrity: sha512-5+VqZryDj4wgCs55o9Lp+p8GE78TLVg0lasCH5xFZ4jacZjtqZa6JUw9/p0WeAojaOfncSM6v77InkFPGnvPvg==} + vite@5.4.18: + resolution: {integrity: sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -5672,10 +5672,10 @@ snapshots: highlight.js: 11.10.0 vue: 3.5.12(typescript@5.6.2) - '@histoire/app@0.17.17(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))': + '@histoire/app@0.17.17(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))': dependencies: - '@histoire/controls': 0.17.17(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) - '@histoire/shared': 0.17.17(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) + '@histoire/controls': 0.17.17(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) + '@histoire/shared': 0.17.17(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) '@histoire/vendors': 0.17.17 '@types/flexsearch': 0.7.6 flexsearch: 0.7.21 @@ -5683,7 +5683,7 @@ snapshots: transitivePeerDependencies: - vite - '@histoire/controls@0.17.17(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))': + '@histoire/controls@0.17.17(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))': dependencies: '@codemirror/commands': 6.7.0 '@codemirror/lang-json': 6.0.1 @@ -5692,26 +5692,26 @@ snapshots: '@codemirror/state': 6.4.1 '@codemirror/theme-one-dark': 6.1.2 '@codemirror/view': 6.34.1 - '@histoire/shared': 0.17.17(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) + '@histoire/shared': 0.17.17(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) '@histoire/vendors': 0.17.17 transitivePeerDependencies: - vite - '@histoire/plugin-vue@0.17.15(histoire@0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)))(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))': + '@histoire/plugin-vue@0.17.15(histoire@0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)))(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))': dependencies: - '@histoire/controls': 0.17.17(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) - '@histoire/shared': 0.17.17(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) + '@histoire/controls': 0.17.17(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) + '@histoire/shared': 0.17.17(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) '@histoire/vendors': 0.17.17 change-case: 4.1.2 globby: 13.2.2 - histoire: 0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) + histoire: 0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) launch-editor: 2.9.1 pathe: 1.1.2 vue: 3.5.12(typescript@5.6.2) transitivePeerDependencies: - vite - '@histoire/shared@0.17.17(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))': + '@histoire/shared@0.17.17(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))': dependencies: '@histoire/vendors': 0.17.17 '@types/fs-extra': 9.0.13 @@ -5719,7 +5719,7 @@ snapshots: chokidar: 3.6.0 pathe: 1.1.2 picocolors: 1.1.0 - vite: 5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) + vite: 5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) '@histoire/vendors@0.17.17': {} @@ -5944,64 +5944,64 @@ snapshots: '@rails/ujs@7.1.400': {} - '@rollup/rollup-android-arm-eabi@4.39.0': + '@rollup/rollup-android-arm-eabi@4.40.0': optional: true - '@rollup/rollup-android-arm64@4.39.0': + '@rollup/rollup-android-arm64@4.40.0': optional: true - '@rollup/rollup-darwin-arm64@4.39.0': + '@rollup/rollup-darwin-arm64@4.40.0': optional: true - '@rollup/rollup-darwin-x64@4.39.0': + '@rollup/rollup-darwin-x64@4.40.0': optional: true - '@rollup/rollup-freebsd-arm64@4.39.0': + '@rollup/rollup-freebsd-arm64@4.40.0': optional: true - '@rollup/rollup-freebsd-x64@4.39.0': + '@rollup/rollup-freebsd-x64@4.40.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.39.0': + '@rollup/rollup-linux-arm-gnueabihf@4.40.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.39.0': + '@rollup/rollup-linux-arm-musleabihf@4.40.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.39.0': + '@rollup/rollup-linux-arm64-gnu@4.40.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.39.0': + '@rollup/rollup-linux-arm64-musl@4.40.0': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.39.0': + '@rollup/rollup-linux-loongarch64-gnu@4.40.0': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.39.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.40.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.39.0': + '@rollup/rollup-linux-riscv64-gnu@4.40.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.39.0': + '@rollup/rollup-linux-riscv64-musl@4.40.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.39.0': + '@rollup/rollup-linux-s390x-gnu@4.40.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.39.0': + '@rollup/rollup-linux-x64-gnu@4.40.0': optional: true - '@rollup/rollup-linux-x64-musl@4.39.0': + '@rollup/rollup-linux-x64-musl@4.40.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.39.0': + '@rollup/rollup-win32-arm64-msvc@4.40.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.39.0': + '@rollup/rollup-win32-ia32-msvc@4.40.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.39.0': + '@rollup/rollup-win32-x64-msvc@4.40.0': optional: true '@rtsao/scc@1.1.0': {} @@ -6802,9 +6802,9 @@ snapshots: global: 4.4.0 is-function: 1.0.2 - '@vitejs/plugin-vue@5.1.4(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))': + '@vitejs/plugin-vue@5.1.4(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))': dependencies: - vite: 5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) + vite: 5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) vue: 3.5.12(typescript@5.6.2) '@vitest/coverage-v8@3.0.5(vitest@3.0.5(@types/node@22.7.0)(jsdom@24.1.3)(sass@1.79.3)(terser@5.33.0))': @@ -6832,13 +6832,13 @@ snapshots: chai: 5.1.2 tinyrainbow: 2.0.0 - '@vitest/mocker@3.0.5(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))': + '@vitest/mocker@3.0.5(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))': dependencies: '@vitest/spy': 3.0.5 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) + vite: 5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) '@vitest/pretty-format@3.0.5': dependencies: @@ -8393,12 +8393,12 @@ snapshots: highlight.js@11.10.0: {} - histoire@0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)): + histoire@0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)): dependencies: '@akryum/tinypool': 0.3.1 - '@histoire/app': 0.17.17(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) - '@histoire/controls': 0.17.17(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) - '@histoire/shared': 0.17.17(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) + '@histoire/app': 0.17.17(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) + '@histoire/controls': 0.17.17(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) + '@histoire/shared': 0.17.17(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) '@histoire/vendors': 0.17.17 '@types/flexsearch': 0.7.6 '@types/markdown-it': 12.2.3 @@ -8425,7 +8425,7 @@ snapshots: sade: 1.8.1 shiki-es: 0.2.0 sirv: 2.0.4 - vite: 5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) + vite: 5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) vite-node: 2.0.1(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) transitivePeerDependencies: - '@types/node' @@ -9766,30 +9766,30 @@ snapshots: dependencies: glob: 7.2.3 - rollup@4.39.0: + rollup@4.40.0: dependencies: '@types/estree': 1.0.7 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.39.0 - '@rollup/rollup-android-arm64': 4.39.0 - '@rollup/rollup-darwin-arm64': 4.39.0 - '@rollup/rollup-darwin-x64': 4.39.0 - '@rollup/rollup-freebsd-arm64': 4.39.0 - '@rollup/rollup-freebsd-x64': 4.39.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.39.0 - '@rollup/rollup-linux-arm-musleabihf': 4.39.0 - '@rollup/rollup-linux-arm64-gnu': 4.39.0 - '@rollup/rollup-linux-arm64-musl': 4.39.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.39.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.39.0 - '@rollup/rollup-linux-riscv64-gnu': 4.39.0 - '@rollup/rollup-linux-riscv64-musl': 4.39.0 - '@rollup/rollup-linux-s390x-gnu': 4.39.0 - '@rollup/rollup-linux-x64-gnu': 4.39.0 - '@rollup/rollup-linux-x64-musl': 4.39.0 - '@rollup/rollup-win32-arm64-msvc': 4.39.0 - '@rollup/rollup-win32-ia32-msvc': 4.39.0 - '@rollup/rollup-win32-x64-msvc': 4.39.0 + '@rollup/rollup-android-arm-eabi': 4.40.0 + '@rollup/rollup-android-arm64': 4.40.0 + '@rollup/rollup-darwin-arm64': 4.40.0 + '@rollup/rollup-darwin-x64': 4.40.0 + '@rollup/rollup-freebsd-arm64': 4.40.0 + '@rollup/rollup-freebsd-x64': 4.40.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.40.0 + '@rollup/rollup-linux-arm-musleabihf': 4.40.0 + '@rollup/rollup-linux-arm64-gnu': 4.40.0 + '@rollup/rollup-linux-arm64-musl': 4.40.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.40.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.40.0 + '@rollup/rollup-linux-riscv64-gnu': 4.40.0 + '@rollup/rollup-linux-riscv64-musl': 4.40.0 + '@rollup/rollup-linux-s390x-gnu': 4.40.0 + '@rollup/rollup-linux-x64-gnu': 4.40.0 + '@rollup/rollup-linux-x64-musl': 4.40.0 + '@rollup/rollup-win32-arm64-msvc': 4.40.0 + '@rollup/rollup-win32-ia32-msvc': 4.40.0 + '@rollup/rollup-win32-x64-msvc': 4.40.0 fsevents: 2.3.3 rope-sequence@1.3.2: {} @@ -10378,7 +10378,7 @@ snapshots: debug: 4.4.0 pathe: 1.1.2 picocolors: 1.1.1 - vite: 5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) + vite: 5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) transitivePeerDependencies: - '@types/node' - less @@ -10390,19 +10390,19 @@ snapshots: - supports-color - terser - vite-plugin-ruby@5.0.0(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)): + vite-plugin-ruby@5.0.0(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)): dependencies: debug: 4.3.5 fast-glob: 3.3.2 - vite: 5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) + vite: 5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) transitivePeerDependencies: - supports-color - vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0): + vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0): dependencies: esbuild: 0.21.5 postcss: 8.5.3 - rollup: 4.39.0 + rollup: 4.40.0 optionalDependencies: '@types/node': 22.7.0 fsevents: 2.3.3 @@ -10412,7 +10412,7 @@ snapshots: vitest@3.0.5(@types/node@22.7.0)(jsdom@24.1.3)(sass@1.79.3)(terser@5.33.0): dependencies: '@vitest/expect': 3.0.5 - '@vitest/mocker': 3.0.5(vite@5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) + '@vitest/mocker': 3.0.5(vite@5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) '@vitest/pretty-format': 3.0.5 '@vitest/runner': 3.0.5 '@vitest/snapshot': 3.0.5 @@ -10428,7 +10428,7 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 5.4.17(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) + vite: 5.4.18(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) vite-node: 2.0.1(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) why-is-node-running: 2.3.0 optionalDependencies: From 9c711bab742b89bc1c24ec144a859671852b6bb3 Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Tue, 22 Apr 2025 05:23:52 +0530 Subject: [PATCH 002/172] fix: Inconsistent widget bubble focus outline shape (#11345) # Pull Request Template ## Description This PR resolves the issue where the focus outline for the standard bubble type appears as a square in Safari, while it appears circular in Chrome. Fixes [CW-4252](https://linear.app/chatwoot/issue/CW-4252/v41-circle-around-campaign-pop-up-warped), https://github.com/chatwoot/chatwoot/issues/11327 **Cause** In Chrome, the focus outline for the standard bubble type is circular, but in Safari, it appears square. This is due to a 20px margin on the SVG inside the bubble. **Solution** The `20px` margin was removed from the SVG, fixing the focus outline to appear circular in Safari browser. ## Type of change - [x] Bug fix (non-breaking change which fixes an issue) ## How Has This Been Tested? ### Loom Video https://www.loom.com/share/cc4244f369f84b98afaef539b79abcfe?sid=e957df16-1a53-4349-8bdc-705b2ed82d45 ### Screenshots **Before** https://www.loom.com/share/e858417722c64df6801ea87e4b89779f?sid=81a0acec-c5f0-4daa-832c-1f23289e2352 image **After** https://www.loom.com/share/3946546382884a33a8fef89f81faf7c2?sid=feeaf18c-2b3d-4d4f-bcdf-70335b456dd1 image ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --- app/javascript/sdk/sdk.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/javascript/sdk/sdk.js b/app/javascript/sdk/sdk.js index 95d132258..0a7191812 100644 --- a/app/javascript/sdk/sdk.js +++ b/app/javascript/sdk/sdk.js @@ -135,7 +135,6 @@ export const SDK_CSS = ` .woot-widget-bubble svg { all: revert; height: 24px; - margin: 20px; width: 24px; } From e3bacd27d817528a83065614038217e29ed23ba5 Mon Sep 17 00:00:00 2001 From: Muhsin Keloth Date: Tue, 22 Apr 2025 20:54:09 +0530 Subject: [PATCH 003/172] feat: Add custom domain to article URL if custom domain exists for the portal (#11349) Portals can have custom domains. When inserting or previewing articles, we consider the frontend URL. This PR fixes article URL generation to properly include the portal's custom domain. --- .../dashboard/helper/portalHelper.js | 49 +++++++++++++++++-- .../helper/specs/portalHelper.spec.js | 42 ++++++++++++++++ .../conversation/ConversationView.vue | 1 + .../ArticleSearch/SearchPopover.vue | 15 +++++- .../pages/PortalsArticlesEditPage.vue | 12 +++-- 5 files changed, 109 insertions(+), 10 deletions(-) diff --git a/app/javascript/dashboard/helper/portalHelper.js b/app/javascript/dashboard/helper/portalHelper.js index 09b648330..ec681ef1b 100644 --- a/app/javascript/dashboard/helper/portalHelper.js +++ b/app/javascript/dashboard/helper/portalHelper.js @@ -1,16 +1,55 @@ -export const buildPortalURL = portalSlug => { - const { hostURL, helpCenterURL } = window.chatwootConfig; +/** + * Formats a custom domain with https protocol if needed + * @param {string} customDomain - The custom domain to format + * @returns {string} Formatted domain with https protocol + */ +const formatCustomDomain = customDomain => + customDomain.startsWith('https') ? customDomain : `https://${customDomain}`; + +/** + * Gets the default base URL from configuration + * @returns {string} The default base URL + * @throws {Error} If no valid base URL is found + */ +const getDefaultBaseURL = () => { + const { hostURL, helpCenterURL } = window.chatwootConfig || {}; const baseURL = helpCenterURL || hostURL || ''; - return `${baseURL}/hc/${portalSlug}`; + + if (!baseURL) { + throw new Error('No valid base URL found in configuration'); + } + + return `${baseURL}/hc`; +}; + +/** + * Gets the base URL from configuration or custom domain + * @param {string} [customDomain] - Optional custom domain for the portal + * @returns {string} The base URL for the portal + */ +const getPortalBaseURL = customDomain => + customDomain ? formatCustomDomain(customDomain) : getDefaultBaseURL(); + +/** + * Builds a portal URL using the provided portal slug and optional custom domain + * @param {string} portalSlug - The slug identifier for the portal + * @param {string} [customDomain] - Optional custom domain for the portal + * @returns {string} The complete portal URL + * @throws {Error} If portalSlug is not provided or invalid + */ +export const buildPortalURL = (portalSlug, customDomain) => { + const baseURL = getPortalBaseURL(customDomain); + return `${baseURL}/${portalSlug}`; }; export const buildPortalArticleURL = ( portalSlug, categorySlug, locale, - articleSlug + articleSlug, + customDomain ) => { - const portalURL = buildPortalURL(portalSlug); + const portalURL = buildPortalURL(portalSlug, customDomain); return `${portalURL}/articles/${articleSlug}`; }; diff --git a/app/javascript/dashboard/helper/specs/portalHelper.spec.js b/app/javascript/dashboard/helper/specs/portalHelper.spec.js index 9c1a47255..daa188b28 100644 --- a/app/javascript/dashboard/helper/specs/portalHelper.spec.js +++ b/app/javascript/dashboard/helper/specs/portalHelper.spec.js @@ -25,5 +25,47 @@ describe('PortalHelper', () => { ).toEqual('https://help.chatwoot.com/hc/handbook/articles/article-slug'); window.chatwootConfig = {}; }); + + it('returns the correct url with custom domain', () => { + window.chatwootConfig = { + hostURL: 'https://app.chatwoot.com', + helpCenterURL: 'https://help.chatwoot.com', + }; + expect( + buildPortalArticleURL( + 'handbook', + 'culture', + 'fr', + 'article-slug', + 'custom-domain.dev' + ) + ).toEqual('https://custom-domain.dev/handbook/articles/article-slug'); + }); + + it('handles https in custom domain correctly', () => { + window.chatwootConfig = { + hostURL: 'https://app.chatwoot.com', + helpCenterURL: 'https://help.chatwoot.com', + }; + expect( + buildPortalArticleURL( + 'handbook', + 'culture', + 'fr', + 'article-slug', + 'https://custom-domain.dev' + ) + ).toEqual('https://custom-domain.dev/handbook/articles/article-slug'); + }); + + it('uses hostURL when helpCenterURL is not available', () => { + window.chatwootConfig = { + hostURL: 'https://app.chatwoot.com', + helpCenterURL: '', + }; + expect( + buildPortalArticleURL('handbook', 'culture', 'fr', 'article-slug') + ).toEqual('https://app.chatwoot.com/hc/handbook/articles/article-slug'); + }); }); }); diff --git a/app/javascript/dashboard/routes/dashboard/conversation/ConversationView.vue b/app/javascript/dashboard/routes/dashboard/conversation/ConversationView.vue index d0e1610e9..4b86841f6 100644 --- a/app/javascript/dashboard/routes/dashboard/conversation/ConversationView.vue +++ b/app/javascript/dashboard/routes/dashboard/conversation/ConversationView.vue @@ -120,6 +120,7 @@ export default { mounted() { this.$store.dispatch('agents/get'); + this.$store.dispatch('portals/index'); this.initialize(); this.$watch('$store.state.route', () => this.initialize()); this.$watch('chatList.length', () => { diff --git a/app/javascript/dashboard/routes/dashboard/helpcenter/components/ArticleSearch/SearchPopover.vue b/app/javascript/dashboard/routes/dashboard/helpcenter/components/ArticleSearch/SearchPopover.vue index 809e58249..f54db1597 100644 --- a/app/javascript/dashboard/routes/dashboard/helpcenter/components/ArticleSearch/SearchPopover.vue +++ b/app/javascript/dashboard/routes/dashboard/helpcenter/components/ArticleSearch/SearchPopover.vue @@ -1,6 +1,7 @@ diff --git a/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactNotes.vue b/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactNotes.vue new file mode 100644 index 000000000..66b6876b1 --- /dev/null +++ b/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactNotes.vue @@ -0,0 +1,51 @@ + + + From fa4c1fadba1a9a43a40d3180f7acee10b024294f Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Tue, 29 Apr 2025 18:12:16 +0530 Subject: [PATCH 016/172] feat: use numbers when fetching from the API (#11391) --- app/services/crm/leadsquared/setup_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/crm/leadsquared/setup_service.rb b/app/services/crm/leadsquared/setup_service.rb index df8a96456..956ff1a10 100644 --- a/app/services/crm/leadsquared/setup_service.rb +++ b/app/services/crm/leadsquared/setup_service.rb @@ -57,7 +57,7 @@ class Crm::Leadsquared::SetupService activity_id = find_or_create_activity_type(activity_type, existing_types) if activity_id.present? - activity_codes[activity_type[:setting_key]] = activity_id + activity_codes[activity_type[:setting_key]] = activity_id.to_i else Rails.logger.error "Failed to find or create activity type: #{activity_type[:name]}" end From 970e76ace8c8326108a7d1d3db09c23d11c9eedb Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Tue, 29 Apr 2025 15:33:11 -0700 Subject: [PATCH 017/172] feat: API Endpoints to update message status (#11387) - Added an api endpoint for update message status ( available only for api inboxes ) - Moved message status management to a service. - Handles case where read status arrive before delivered fixes: #10314 , #9962 --- .../conversations/messages_controller.rb | 19 +++++- .../update_message_status_job.rb | 2 +- .../facebook/send_on_facebook_service.rb | 8 +-- app/services/instagram/base_send_service.rb | 2 +- app/services/line/send_on_line_service.rb | 4 +- .../messages/status_update_service.rb | 34 ++++++++++ app/services/twilio/send_on_twilio_service.rb | 2 +- .../messages/update.json.jbuilder | 1 + app/workers/email_reply_worker.rb | 2 +- config/routes.rb | 2 +- lib/webhooks/trigger.rb | 2 +- .../conversations/messages_controller_spec.rb | 64 ++++++++++++++++++- .../messages/status_update_service_spec.rb | 46 +++++++++++++ 13 files changed, 173 insertions(+), 15 deletions(-) create mode 100644 app/services/messages/status_update_service.rb create mode 100644 app/views/api/v1/accounts/conversations/messages/update.json.jbuilder create mode 100644 spec/services/messages/status_update_service_spec.rb diff --git a/app/controllers/api/v1/accounts/conversations/messages_controller.rb b/app/controllers/api/v1/accounts/conversations/messages_controller.rb index 63226f342..67381a715 100644 --- a/app/controllers/api/v1/accounts/conversations/messages_controller.rb +++ b/app/controllers/api/v1/accounts/conversations/messages_controller.rb @@ -1,4 +1,6 @@ class Api::V1::Accounts::Conversations::MessagesController < Api::V1::Accounts::Conversations::BaseController + before_action :ensure_api_inbox, only: :update + def index @messages = message_finder.perform end @@ -11,6 +13,11 @@ class Api::V1::Accounts::Conversations::MessagesController < Api::V1::Accounts:: render_could_not_create_error(e.message) end + def update + Messages::StatusUpdateService.new(message, permitted_params[:status], permitted_params[:external_error]).perform + @message = message + end + def destroy ActiveRecord::Base.transaction do message.update!(content: I18n.t('conversations.messages.deleted'), content_type: :text, content_attributes: { deleted: true }) @@ -21,7 +28,9 @@ class Api::V1::Accounts::Conversations::MessagesController < Api::V1::Accounts:: def retry return if message.blank? - message.update!(status: :sent, content_attributes: {}) + service = Messages::StatusUpdateService.new(message, 'sent') + service.perform + message.update!(content_attributes: {}) ::SendReplyJob.perform_later(message.id) rescue StandardError => e render_could_not_create_error(e.message) @@ -56,10 +65,16 @@ class Api::V1::Accounts::Conversations::MessagesController < Api::V1::Accounts:: end def permitted_params - params.permit(:id, :target_language) + params.permit(:id, :target_language, :status, :external_error) end def already_translated_content_available? message.translations.present? && message.translations[permitted_params[:target_language]].present? end + + # API inbox check + def ensure_api_inbox + # Only API inboxes can update messages + render json: { error: 'Message status update is only allowed for API inboxes' }, status: :forbidden unless @conversation.inbox.api? + end end diff --git a/app/jobs/conversations/update_message_status_job.rb b/app/jobs/conversations/update_message_status_job.rb index 1e6333b41..6fcef4361 100644 --- a/app/jobs/conversations/update_message_status_job.rb +++ b/app/jobs/conversations/update_message_status_job.rb @@ -15,7 +15,7 @@ class Conversations::UpdateMessageStatusJob < ApplicationJob conversation.messages.where(status: %w[sent delivered]) .where.not(message_type: 'incoming') .where('messages.created_at <= ?', timestamp).find_each do |message| - message.update!(status: status) + Messages::StatusUpdateService.new(message, status).perform end end end diff --git a/app/services/facebook/send_on_facebook_service.rb b/app/services/facebook/send_on_facebook_service.rb index 5dde19c5a..5e9212edd 100644 --- a/app/services/facebook/send_on_facebook_service.rb +++ b/app/services/facebook/send_on_facebook_service.rb @@ -16,7 +16,7 @@ class Facebook::SendOnFacebookService < Base::SendOnChannelService rescue Facebook::Messenger::FacebookError => e # TODO : handle specific errors or else page will get disconnected handle_facebook_error(e) - message.update!(status: :failed, external_error: e.message) + Messages::StatusUpdateService.new(message, 'failed', e.message).perform end def send_message_to_facebook(delivery_params) @@ -24,7 +24,7 @@ class Facebook::SendOnFacebookService < Base::SendOnChannelService return if parsed_result.nil? if parsed_result['error'].present? - message.update!(status: :failed, external_error: external_error(parsed_result)) + Messages::StatusUpdateService.new(message, 'failed', external_error(parsed_result)).perform Rails.logger.info "Facebook::SendOnFacebookService: Error sending message to Facebook : Page - #{channel.page_id} : #{parsed_result}" end @@ -35,11 +35,11 @@ class Facebook::SendOnFacebookService < Base::SendOnChannelService result = Facebook::Messenger::Bot.deliver(delivery_params, page_id: channel.page_id) JSON.parse(result) rescue JSON::ParserError - message.update!(status: :failed, external_error: 'Facebook was unable to process this request') + Messages::StatusUpdateService.new(message, 'failed', 'Facebook was unable to process this request').perform Rails.logger.error "Facebook::SendOnFacebookService: Error parsing JSON response from Facebook : Page - #{channel.page_id} : #{result}" nil rescue Net::OpenTimeout - message.update!(status: :failed, external_error: 'Request timed out, please try again later') + Messages::StatusUpdateService.new(message, 'failed', 'Request timed out, please try again later').perform Rails.logger.error "Facebook::SendOnFacebookService: Timeout error sending message to Facebook : Page - #{channel.page_id}" nil end diff --git a/app/services/instagram/base_send_service.rb b/app/services/instagram/base_send_service.rb index dee41c23f..ff5f9216e 100644 --- a/app/services/instagram/base_send_service.rb +++ b/app/services/instagram/base_send_service.rb @@ -61,7 +61,7 @@ class Instagram::BaseSendService < Base::SendOnChannelService else external_error = external_error(parsed_response) Rails.logger.error("Instagram response: #{external_error} : #{message_content}") - message.update!(status: :failed, external_error: external_error) + Messages::StatusUpdateService.new(message, 'failed', external_error).perform nil end end diff --git a/app/services/line/send_on_line_service.rb b/app/services/line/send_on_line_service.rb index f8d704128..03ebe0ab7 100644 --- a/app/services/line/send_on_line_service.rb +++ b/app/services/line/send_on_line_service.rb @@ -14,10 +14,10 @@ class Line::SendOnLineService < Base::SendOnChannelService if response.code == '200' # If the request is successful, update the message status to delivered - message.update!(status: :delivered) + Messages::StatusUpdateService.new(message, 'delivered').perform else # If the request is not successful, update the message status to failed and save the external error - message.update!(status: :failed, external_error: external_error(parsed_json)) + Messages::StatusUpdateService.new(message, 'failed', external_error(parsed_json)).perform end end diff --git a/app/services/messages/status_update_service.rb b/app/services/messages/status_update_service.rb new file mode 100644 index 000000000..4868a201e --- /dev/null +++ b/app/services/messages/status_update_service.rb @@ -0,0 +1,34 @@ +class Messages::StatusUpdateService + attr_reader :message, :status, :external_error + + def initialize(message, status, external_error = nil) + @message = message + @status = status + @external_error = external_error + end + + def perform + return false unless valid_status_transition? + + update_message_status + end + + private + + def update_message_status + # Update status and set external_error only when failed + message.update!( + status: status, + external_error: (status == 'failed' ? external_error : nil) + ) + end + + def valid_status_transition? + return false unless Message.statuses.key?(status) + + # Don't allow changing from 'read' to 'delivered' + return false if message.read? && status == 'delivered' + + true + end +end diff --git a/app/services/twilio/send_on_twilio_service.rb b/app/services/twilio/send_on_twilio_service.rb index 3fc420bb2..5bd262759 100644 --- a/app/services/twilio/send_on_twilio_service.rb +++ b/app/services/twilio/send_on_twilio_service.rb @@ -9,7 +9,7 @@ class Twilio::SendOnTwilioService < Base::SendOnChannelService begin twilio_message = channel.send_message(**message_params) rescue Twilio::REST::TwilioError, Twilio::REST::RestError => e - message.update!(status: :failed, external_error: e.message) + Messages::StatusUpdateService.new(message, 'failed', e.message).perform end message.update!(source_id: twilio_message.sid) if twilio_message end diff --git a/app/views/api/v1/accounts/conversations/messages/update.json.jbuilder b/app/views/api/v1/accounts/conversations/messages/update.json.jbuilder new file mode 100644 index 000000000..3798b6c1f --- /dev/null +++ b/app/views/api/v1/accounts/conversations/messages/update.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'api/v1/models/message', message: @message diff --git a/app/workers/email_reply_worker.rb b/app/workers/email_reply_worker.rb index 20cc70d5e..14b668637 100644 --- a/app/workers/email_reply_worker.rb +++ b/app/workers/email_reply_worker.rb @@ -11,6 +11,6 @@ class EmailReplyWorker ConversationReplyMailer.with(account: message.account).email_reply(message).deliver_now rescue StandardError => e ChatwootExceptionTracker.new(e, account: message.account).capture_exception - message.update!(status: :failed, external_error: e.message) + Messages::StatusUpdateService.new(message, 'failed', e.message).perform end end diff --git a/config/routes.rb b/config/routes.rb index 46199db12..6c71a8cc6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -98,7 +98,7 @@ Rails.application.routes.draw do post :filter end scope module: :conversations do - resources :messages, only: [:index, :create, :destroy] do + resources :messages, only: [:index, :create, :destroy, :update] do member do post :translate post :retry diff --git a/lib/webhooks/trigger.rb b/lib/webhooks/trigger.rb index f2e66f997..41b3a415d 100644 --- a/lib/webhooks/trigger.rb +++ b/lib/webhooks/trigger.rb @@ -42,7 +42,7 @@ class Webhooks::Trigger end def update_message_status(error) - message.update!(status: :failed, external_error: error.message) + Messages::StatusUpdateService.new(message, 'failed', error.message).perform end def message diff --git a/spec/controllers/api/v1/accounts/conversations/messages_controller_spec.rb b/spec/controllers/api/v1/accounts/conversations/messages_controller_spec.rb index 94d4cf272..f7ff042e5 100644 --- a/spec/controllers/api/v1/accounts/conversations/messages_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/conversations/messages_controller_spec.rb @@ -84,7 +84,6 @@ RSpec.describe 'Conversation Messages API', type: :request do context 'when api inbox' do let(:api_channel) { create(:channel_api, account: account) } let(:api_inbox) { create(:inbox, channel: api_channel, account: account) } - let(:inbox_member) { create(:inbox_member, user: agent, inbox: api_inbox) } let(:conversation) { create(:conversation, inbox: api_inbox, account: account) } it 'reopens the conversation with new incoming message' do @@ -294,4 +293,67 @@ RSpec.describe 'Conversation Messages API', type: :request do end end end + + describe 'PATCH /api/v1/accounts/{account.id}/conversations/:conversation_id/messages/:id' do + let(:api_channel) { create(:channel_api, account: account) } + let(:api_inbox) { create(:inbox, channel: api_channel, account: account) } + let(:agent) { create(:user, account: account, role: :agent) } + let!(:conversation) { create(:conversation, inbox: api_inbox, account: account) } + let!(:message) { create(:message, conversation: conversation, account: account, status: :sent) } + + context 'when unauthenticated' do + it 'returns unauthorized' do + patch api_v1_account_conversation_message_url(account_id: account.id, conversation_id: conversation.display_id, id: message.id) + expect(response).to have_http_status(:unauthorized) + end + end + + context 'when authenticated agent' do + context 'when agent has non-API inbox' do + let(:inbox) { create(:inbox, account: account) } + let(:agent) { create(:user, account: account, role: :agent) } + let!(:conversation) { create(:conversation, inbox: inbox, account: account) } + + before { create(:inbox_member, inbox: inbox, user: agent) } + + it 'returns forbidden' do + patch api_v1_account_conversation_message_url( + account_id: account.id, + conversation_id: conversation.display_id, + id: message.id + ), params: { status: 'failed', external_error: 'err' }, headers: agent.create_new_auth_token, as: :json + expect(response).to have_http_status(:forbidden) + end + end + + context 'when agent has API inbox' do + before { create(:inbox_member, inbox: api_inbox, user: agent) } + + it 'uses StatusUpdateService to perform status update' do + service = instance_double(Messages::StatusUpdateService) + expect(Messages::StatusUpdateService).to receive(:new) + .with(message, 'failed', 'err123') + .and_return(service) + expect(service).to receive(:perform) + patch api_v1_account_conversation_message_url( + account_id: account.id, + conversation_id: conversation.display_id, + id: message.id + ), params: { status: 'failed', external_error: 'err123' }, headers: agent.create_new_auth_token, as: :json + end + + it 'updates status to failed with external_error' do + patch api_v1_account_conversation_message_url( + account_id: account.id, + conversation_id: conversation.display_id, + id: message.id + ), params: { status: 'failed', external_error: 'err123' }, headers: agent.create_new_auth_token, as: :json + + expect(response).to have_http_status(:success) + expect(message.reload.status).to eq('failed') + expect(message.reload.external_error).to eq('err123') + end + end + end + end end diff --git a/spec/services/messages/status_update_service_spec.rb b/spec/services/messages/status_update_service_spec.rb new file mode 100644 index 000000000..ce8fc2163 --- /dev/null +++ b/spec/services/messages/status_update_service_spec.rb @@ -0,0 +1,46 @@ +require 'rails_helper' + +describe Messages::StatusUpdateService do + let(:account) { create(:account) } + let(:conversation) { create(:conversation, account: account) } + let(:message) { create(:message, conversation: conversation, account: account) } + + describe '#perform' do + context 'when status is valid' do + it 'updates the status of the message' do + service = described_class.new(message, 'delivered') + service.perform + expect(message.reload.status).to eq('delivered') + end + + it 'clears external_error when status is not failed' do + message.update!(status: 'failed', external_error: 'previous error') + service = described_class.new(message, 'delivered') + service.perform + expect(message.reload.status).to eq('delivered') + expect(message.reload.external_error).to be_nil + end + + it 'updates external_error when status is failed' do + service = described_class.new(message, 'failed', 'some error') + service.perform + expect(message.reload.status).to eq('failed') + expect(message.reload.external_error).to eq('some error') + end + end + + context 'when status is invalid' do + it 'returns false for invalid status' do + service = described_class.new(message, 'invalid_status') + expect(service.perform).to be false + end + + it 'prevents transition from read to delivered' do + message.update!(status: 'read') + service = described_class.new(message, 'delivered') + expect(service.perform).to be false + expect(message.reload.status).to eq('read') + end + end + end +end From fb6409508b916da0e1daff583f0fcfc7c54505b5 Mon Sep 17 00:00:00 2001 From: Pranav Date: Tue, 29 Apr 2025 15:42:15 -0700 Subject: [PATCH 018/172] feat: Allow customizing the responses, flows in Captain (#11385) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ability to provide custom instructions to captain Screenshot 2025-04-28 at 6 11 43 PM --- .../dashboard/api/captain/assistant.js | 7 + .../components-next/Accordion/Accordion.vue | 39 +++ .../components-next/captain/PageLayout.vue | 19 +- .../captain/assistant/AssistantCard.vue | 7 +- .../captain/assistant/AssistantPlayground.vue | 111 +++++++ .../captain/assistant/MessageList.vue | 91 ++++++ .../assistant/EditAssistantForm.vue | 306 ++++++++++++++++++ .../i18n/locale/en/integrations.json | 48 ++- .../dashboard/captain/assistants/Edit.vue | 71 ++++ .../dashboard/captain/assistants/Index.vue | 6 +- .../dashboard/captain/captain.routes.js | 14 + config/routes.rb | 3 + .../accounts/captain/assistants_controller.rb | 26 +- enterprise/app/helpers/captain/chat_helper.rb | 27 +- .../conversation/response_builder_job.rb | 2 +- ...ox_pending_conversations_resolution_job.rb | 3 +- .../app/policies/captain/assistant_policy.rb | 4 + .../captain/llm/assistant_chat_service.rb | 2 +- .../captain/llm/system_prompts_service.rb | 4 +- .../captain/assistants_controller_spec.rb | 63 ++++ ...nding_conversations_resolution_job_spec.rb | 2 + 21 files changed, 823 insertions(+), 32 deletions(-) create mode 100644 app/javascript/dashboard/components-next/Accordion/Accordion.vue create mode 100644 app/javascript/dashboard/components-next/captain/assistant/AssistantPlayground.vue create mode 100644 app/javascript/dashboard/components-next/captain/assistant/MessageList.vue create mode 100644 app/javascript/dashboard/components-next/captain/pageComponents/assistant/EditAssistantForm.vue create mode 100644 app/javascript/dashboard/routes/dashboard/captain/assistants/Edit.vue diff --git a/app/javascript/dashboard/api/captain/assistant.js b/app/javascript/dashboard/api/captain/assistant.js index ce636e526..157eba74e 100644 --- a/app/javascript/dashboard/api/captain/assistant.js +++ b/app/javascript/dashboard/api/captain/assistant.js @@ -14,6 +14,13 @@ class CaptainAssistant extends ApiClient { }, }); } + + playground({ assistantId, messageContent, messageHistory }) { + return axios.post(`${this.url}/${assistantId}/playground`, { + message_content: messageContent, + message_history: messageHistory, + }); + } } export default new CaptainAssistant(); diff --git a/app/javascript/dashboard/components-next/Accordion/Accordion.vue b/app/javascript/dashboard/components-next/Accordion/Accordion.vue new file mode 100644 index 000000000..f75a2ef25 --- /dev/null +++ b/app/javascript/dashboard/components-next/Accordion/Accordion.vue @@ -0,0 +1,39 @@ + + + diff --git a/app/javascript/dashboard/components-next/captain/PageLayout.vue b/app/javascript/dashboard/components-next/captain/PageLayout.vue index e9fae9ca7..7355ac616 100644 --- a/app/javascript/dashboard/components-next/captain/PageLayout.vue +++ b/app/javascript/dashboard/components-next/captain/PageLayout.vue @@ -2,6 +2,7 @@ import { computed } from 'vue'; import { usePolicy } from 'dashboard/composables/usePolicy'; import Button from 'dashboard/components-next/button/Button.vue'; +import BackButton from 'dashboard/components/widgets/BackButton.vue'; import PaginationFooter from 'dashboard/components-next/pagination/PaginationFooter.vue'; import Spinner from 'dashboard/components-next/spinner/Spinner.vue'; import Policy from 'dashboard/components/policy.vue'; @@ -23,6 +24,10 @@ const props = defineProps({ type: String, default: '', }, + backUrl: { + type: [String, Object], + default: '', + }, buttonPolicy: { type: Array, default: () => [], @@ -39,6 +44,10 @@ const props = defineProps({ type: Boolean, default: false, }, + showKnowMore: { + type: Boolean, + default: true, + }, isEmpty: { type: Boolean, default: false, @@ -73,19 +82,23 @@ const handlePageChange = event => { class="flex items-start lg:items-center justify-between w-full py-6 lg:py-0 lg:h-20 gap-4 lg:gap-2 flex-col lg:flex-row" >
+ {{ headerTitle }} -
+
@@ -104,7 +117,7 @@ const handlePageChange = event => {
-
+
{