diff --git a/.circleci/config.yml b/.circleci/config.yml
index 15c40dc77..459faf1c8 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -1,84 +1,87 @@
-# Ruby CircleCI 2.0 configuration file
-#
-# Check https://circleci.com/docs/2.0/language-ruby/ for more details
-#
-version: 2
+version: 2.1
+orbs:
+ node: circleci/node@6.1.0
+
defaults: &defaults
working_directory: ~/build
- docker:
- # specify the version you desire here
- - image: cimg/ruby:3.3.3-browsers
-
- # Specify service dependencies here if necessary
- # CircleCI maintains a library of pre-built images
- # documented at https://circleci.com/docs/2.0/circleci-images/
- - image: cimg/postgres:15.3
- - image: cimg/redis:6.2.6
- environment:
- - RAILS_LOG_TO_STDOUT: false
- - COVERAGE: true
- - LOG_LEVEL: warn
- parallelism: 4
+ machine:
+ image: ubuntu-2204:2024.05.1
resource_class: large
+ environment:
+ RAILS_LOG_TO_STDOUT: false
+ COVERAGE: true
+ LOG_LEVEL: warn
+ parallelism: 4
jobs:
build:
<<: *defaults
steps:
- checkout
+ - node/install:
+ node-version: '20.12'
+ - node/install-pnpm
+ - node/install-packages:
+ pkg-manager: pnpm
+ override-ci-command: pnpm i
+ - run: node --version
+ - run: pnpm --version
- run:
- name: Configure Bundler
+ name: Install System Dependencies
command: |
- echo 'export BUNDLER_VERSION=$(cat Gemfile.lock | tail -1 | tr -d " ")' >> $BASH_ENV
- source $BASH_ENV
+ sudo apt-get update
+ DEBIAN_FRONTEND=noninteractive sudo apt-get install -y \
+ libpq-dev \
+ redis-server \
+ postgresql \
+ build-essential \
+ git \
+ curl \
+ libssl-dev \
+ zlib1g-dev \
+ libreadline-dev \
+ libyaml-dev \
+ openjdk-11-jdk \
+ jq \
+ software-properties-common \
+ ca-certificates \
+ imagemagick \
+ libxml2-dev \
+ libxslt1-dev \
+ file \
+ g++ \
+ gcc \
+ autoconf \
+ gnupg2 \
+ patch \
+ ruby-dev \
+ liblzma-dev \
+ libgmp-dev \
+ libncurses5-dev \
+ libffi-dev \
+ libgdbm6 \
+ libgdbm-dev \
+ libvips
+
+ - run:
+ name: Install RVM and Ruby 3.3.3
+ command: |
+ sudo apt-get install -y gpg
+ gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
+ \curl -sSL https://get.rvm.io | bash -s stable
+ echo 'source ~/.rvm/scripts/rvm' >> $BASH_ENV
+ source ~/.rvm/scripts/rvm
+ rvm install "3.3.3"
+ rvm use 3.3.3 --default
gem install bundler
- run:
- name: Which bundler?
- command: bundle -v
-
- - run:
- name: Swap node versions
+ name: Install Application Dependencies
command: |
- set +e
- wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
- export NVM_DIR="$HOME/.nvm"
- [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
- [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
- nvm install v20
- echo 'export NVM_DIR="$HOME/.nvm"' >> $BASH_ENV
- echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> $BASH_ENV
-
- # Run bundler
- # Load installed gems from cache if possible, bundle install then save cache
- # Multiple caches are used to increase the chance of a cache hit
-
- - restore_cache:
- keys:
- - chatwoot-bundle-{{ .Environment.CACHE_VERSION }}-v20220524-{{ checksum "Gemfile.lock" }}
-
- - run: bundle install --frozen --path ~/.bundle
- - save_cache:
- paths:
- - ~/.bundle
- key: chatwoot-bundle-{{ .Environment.CACHE_VERSION }}-v20220524-{{ checksum "Gemfile.lock" }}
-
- # Only necessary if app uses webpacker or yarn in some other way
- - restore_cache:
- keys:
- - chatwoot-yarn-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }}
- - chatwoot-yarn-
-
- - run:
- name: yarn
- command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
-
- # Store yarn / webpacker cache
- - save_cache:
- key: chatwoot-yarn-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }}
- paths:
- - ~/.cache/yarn
+ source ~/.rvm/scripts/rvm
+ bundle install
+ # pnpm install
- run:
name: Download cc-test-reporter
@@ -86,12 +89,8 @@ jobs:
mkdir -p ~/tmp
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ~/tmp/cc-test-reporter
chmod +x ~/tmp/cc-test-reporter
- - persist_to_workspace:
- root: ~/tmp
- paths:
- - cc-test-reporter
- # verify swagger specification
+ # Swagger verification
- run:
name: Verify swagger API specification
command: |
@@ -104,45 +103,62 @@ jobs:
curl -L https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/6.3.0/openapi-generator-cli-6.3.0.jar > ~/tmp/openapi-generator-cli-6.3.0.jar
java -jar ~/tmp/openapi-generator-cli-6.3.0.jar validate -i swagger/swagger.json
- # Database setup
- - run: bundle exec rake db:create
- - run: bundle exec rake db:schema:load
+ # we remove the FRONTED_URL from the .env before running the tests
+ - run:
+ name: Database Setup and Configure Environment Variables
+ command: |
+ pg_pass=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 15 ; echo '')
+ sed -i "s/REPLACE_WITH_PASSWORD/${pg_pass}/g" ${PWD}/.circleci/setup_chatwoot.sql
+ chmod 644 ${PWD}/.circleci/setup_chatwoot.sql
+ mv ${PWD}/.circleci/setup_chatwoot.sql /tmp/
+ sudo -i -u postgres psql -f /tmp/setup_chatwoot.sql
+ cp .env.example .env
+ sed -i '/^FRONTEND_URL/d' .env
+ sed -i -e '/REDIS_URL/ s/=.*/=redis:\/\/localhost:6379/' .env
+ sed -i -e '/POSTGRES_HOST/ s/=.*/=localhost/' .env
+ sed -i -e '/POSTGRES_USERNAME/ s/=.*/=chatwoot/' .env
+ sed -i -e "/POSTGRES_PASSWORD/ s/=.*/=$pg_pass/" .env
+ echo -en "\nINSTALLATION_ENV=circleci" >> ".env"
+ # Database setup
+ - run:
+ name: Run DB migrations
+ command: bundle exec rails db:chatwoot_prepare
+
+ # Bundle audit
- run:
name: Bundle audit
command: bundle exec bundle audit update && bundle exec bundle audit check -v
+ # Rubocop linting
- run:
name: Rubocop
command: bundle exec rubocop
- # - run:
- # name: Brakeman
- # command: bundle exec brakeman
-
+ # ESLint linting
- run:
name: eslint
- command: yarn run eslint
+ command: pnpm run eslint
- # Run frontend tests
- run:
name: Run frontend tests
command: |
- mkdir -p ~/tmp/test-results/frontend_specs
+ mkdir -p ~/build/coverage/frontend
~/tmp/cc-test-reporter before-build
- yarn test:coverage
- - run:
- name: Code Climate Test Coverage
- command: |
- ~/tmp/cc-test-reporter format-coverage -t lcov -o "coverage/codeclimate.frontend_$CIRCLE_NODE_INDEX.json"
+ pnpm run test:coverage
- # Run rails tests
+ - run:
+ name: Code Climate Test Coverage (Frontend)
+ command: |
+ ~/tmp/cc-test-reporter format-coverage -t lcov -o "~/build/coverage/frontend/codeclimate.frontend_$CIRCLE_NODE_INDEX.json"
+
+ # Run backend tests
- run:
name: Run backend tests
command: |
mkdir -p ~/tmp/test-results/rspec
mkdir -p ~/tmp/test-artifacts
- mkdir -p coverage
+ mkdir -p ~/build/coverage/backend
~/tmp/cc-test-reporter before-build
TESTFILES=$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)
bundle exec rspec --format progress \
@@ -150,54 +166,18 @@ jobs:
--out ~/tmp/test-results/rspec.xml \
-- ${TESTFILES}
no_output_timeout: 30m
+
- run:
- name: Code Climate Test Coverage
+ name: Code Climate Test Coverage (Backend)
command: |
- ~/tmp/cc-test-reporter format-coverage -t simplecov -o "coverage/codeclimate.$CIRCLE_NODE_INDEX.json"
+ ~/tmp/cc-test-reporter format-coverage -t simplecov -o "~/build/coverage/backend/codeclimate.$CIRCLE_NODE_INDEX.json"
+
+ - run:
+ name: List coverage directory contents
+ command: |
+ ls -R ~/build/coverage
- persist_to_workspace:
- root: coverage
+ root: ~/build
paths:
- - codeclimate.*.json
- # collect reports
- - store_test_results:
- path: ~/tmp/test-results
- - store_artifacts:
- path: ~/tmp/test-artifacts
- - store_artifacts:
- path: log
-
- upload-coverage:
- working_directory: ~/build
- docker:
- # specify the version you desire here
- - image: circleci/ruby:3.0.2-node-browsers
- environment:
- - CC_TEST_REPORTER_ID: caf26a895e937974a90860cfadfded20891cfd1373a5aaafb3f67406ab9d433f
- steps:
- - attach_workspace:
- at: ~/build
- - run:
- name: Download cc-test-reporter
- command: |
- mkdir -p ~/tmp
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ~/tmp/cc-test-reporter
- chmod +x ~/tmp/cc-test-reporter
- - persist_to_workspace:
- root: ~/tmp
- paths:
- - cc-test-reporter
- - run:
- name: Upload coverage results to Code Climate
- command: |
- ~/tmp/cc-test-reporter sum-coverage --output - codeclimate.*.json | ~/tmp/cc-test-reporter upload-coverage --debug --input -
-
-workflows:
- version: 2
-
- commit:
- jobs:
- - build
- - upload-coverage:
- requires:
- - build
+ - coverage
diff --git a/.circleci/setup_chatwoot.sql b/.circleci/setup_chatwoot.sql
new file mode 100644
index 000000000..4e5430f1d
--- /dev/null
+++ b/.circleci/setup_chatwoot.sql
@@ -0,0 +1,11 @@
+CREATE USER chatwoot CREATEDB;
+ALTER USER chatwoot PASSWORD 'REPLACE_WITH_PASSWORD';
+ALTER ROLE chatwoot SUPERUSER;
+
+UPDATE pg_database SET datistemplate = FALSE WHERE datname = 'template1';
+DROP DATABASE template1;
+CREATE DATABASE template1 WITH TEMPLATE = template0 ENCODING = 'UNICODE';
+UPDATE pg_database SET datistemplate = TRUE WHERE datname = 'template1';
+
+\c template1;
+VACUUM FREEZE;
diff --git a/.codeclimate.yml b/.codeclimate.yml
index d8b8d985b..5e16262da 100644
--- a/.codeclimate.yml
+++ b/.codeclimate.yml
@@ -27,7 +27,8 @@ checks:
threshold: 50
exclude_patterns:
- 'spec/'
- - '**/specs/'
+ - '**/specs/**/**'
+ - '**/spec/**/**'
- 'db/*'
- 'bin/**/*'
- 'db/**/*'
diff --git a/.eslintrc.js b/.eslintrc.js
index f3d050ab3..a2932b2a9 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -2,16 +2,36 @@ module.exports = {
extends: [
'airbnb-base/legacy',
'prettier',
- 'plugin:vue/recommended',
- 'plugin:storybook/recommended',
- 'plugin:cypress/recommended',
+ 'plugin:vue/vue3-recommended',
+ 'plugin:vitest-globals/recommended',
],
+ overrides: [
+ {
+ files: ['**/*.spec.{j,t}s?(x)'],
+ env: {
+ 'vitest-globals/env': true,
+ },
+ },
+ {
+ files: ['**/*.story.vue'],
+ rules: {
+ 'vue/no-undef-components': [
+ 'error',
+ {
+ ignorePatterns: ['Variant', 'Story'],
+ },
+ ],
+ // Story files can have static strings, it doesn't need to handle i18n always.
+ 'vue/no-bare-strings-in-template': 'off',
+ 'no-console': 'off',
+ },
+ },
+ ],
+ plugins: ['html', 'prettier'],
parserOptions: {
- parser: '@babel/eslint-parser',
- ecmaVersion: 2020,
+ ecmaVersion: 'latest',
sourceType: 'module',
},
- plugins: ['html', 'prettier', 'babel'],
rules: {
'prettier/prettier': ['error'],
camelcase: 'off',
@@ -210,13 +230,6 @@ module.exports = {
'import/extensions': ['off'],
'no-console': 'error',
},
- settings: {
- 'import/resolver': {
- webpack: {
- config: 'config/webpack/resolve.js',
- },
- },
- },
env: {
browser: true,
node: true,
diff --git a/.github/workflows/frontend-fe.yml b/.github/workflows/frontend-fe.yml
new file mode 100644
index 000000000..15bb6f5e9
--- /dev/null
+++ b/.github/workflows/frontend-fe.yml
@@ -0,0 +1,43 @@
+name: Frontend Lint & Test
+
+on:
+ push:
+ branches:
+ - develop
+ pull_request:
+ branches:
+ - develop
+
+jobs:
+ test:
+ runs-on: ubuntu-20.04
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.pull_request.head.ref }}
+ repository: ${{ github.event.pull_request.head.repo.full_name }}
+
+ - uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - uses: pnpm/action-setup@v4
+ with:
+ version: 9.3.0
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ cache: 'pnpm'
+
+ - name: Install pnpm dependencies
+ run: pnpm install --frozen-lockfile
+
+ - name: Run eslint
+ run: pnpm run eslint
+
+ - name: Run frontend tests with coverage
+ run: |
+ mkdir -p coverage
+ pnpm run test:coverage
diff --git a/.github/workflows/run_foss_spec.yml b/.github/workflows/run_foss_spec.yml
index b0b2372ae..6a018b314 100644
--- a/.github/workflows/run_foss_spec.yml
+++ b/.github/workflows/run_foss_spec.yml
@@ -21,7 +21,7 @@ jobs:
image: postgres:15.3
env:
POSTGRES_USER: postgres
- POSTGRES_PASSWORD: ""
+ POSTGRES_PASSWORD: ''
POSTGRES_DB: postgres
POSTGRES_HOST_AUTH_METHOD: trust
ports:
@@ -41,47 +41,49 @@ jobs:
options: --entrypoint redis-server
steps:
- - uses: actions/checkout@v4
- with:
- ref: ${{ github.event.pull_request.head.ref }}
- repository: ${{ github.event.pull_request.head.repo.full_name }}
+ - uses: actions/checkout@v4
+ - uses: pnpm/action-setup@v4
+ with:
+ version: 9
+ ref: ${{ github.event.pull_request.head.ref }}
+ repository: ${{ github.event.pull_request.head.repo.full_name }}
- - uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true # runs 'bundle install' and caches installed gems automatically
+ - uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- - uses: actions/setup-node@v4
- with:
- node-version: 20
- cache: yarn
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ cache: 'pnpm'
- - name: yarn
- run: yarn install
+ - name: Install pnpm dependencies
+ run: pnpm i
- - name: Strip enterprise code
- run: |
- rm -rf enterprise
- rm -rf spec/enterprise
+ - name: Strip enterprise code
+ run: |
+ rm -rf enterprise
+ rm -rf spec/enterprise
- - name: Create database
- run: bundle exec rake db:create
+ - name: Create database
+ run: bundle exec rake db:create
- - name: Seed database
- run: bundle exec rake db:schema:load
+ - name: Seed database
+ run: bundle exec rake db:schema:load
- - name: yarn check-files
- run: yarn install --check-files
+ - name: Run frontend tests
+ run: pnpm run test:coverage
- # Run rails tests
- - name: Run backend tests
- run: |
- bundle exec rspec --profile=10 --format documentation
- env:
- NODE_OPTIONS: --openssl-legacy-provider
+ # Run rails tests
+ - name: Run backend tests
+ run: |
+ bundle exec rspec --profile=10 --format documentation
+ env:
+ NODE_OPTIONS: --openssl-legacy-provider
- - name: Upload rails log folder
- uses: actions/upload-artifact@v4
- if: always()
- with:
- name: rails-log-folder
- path: log
+ - name: Upload rails log folder
+ uses: actions/upload-artifact@v4
+ if: always()
+ with:
+ name: rails-log-folder
+ path: log
diff --git a/.github/workflows/run_response_bot_spec.yml b/.github/workflows/run_response_bot_spec.yml
index c594ff404..c788a0400 100644
--- a/.github/workflows/run_response_bot_spec.yml
+++ b/.github/workflows/run_response_bot_spec.yml
@@ -49,13 +49,17 @@ jobs:
with:
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
+ - uses: pnpm/action-setup@v2
+ with:
+ version: 9.3.0
+
- uses: actions/setup-node@v4
with:
node-version: 20
- cache: yarn
+ cache: pnpm
- - name: yarn
- run: yarn install
+ - name: pnpm
+ run: pnpm install
- name: Create database
run: bundle exec rake db:create
diff --git a/.github/workflows/size-limit.yml b/.github/workflows/size-limit.yml
index 0526aeedb..0758ca7d0 100644
--- a/.github/workflows/size-limit.yml
+++ b/.github/workflows/size-limit.yml
@@ -19,23 +19,33 @@ jobs:
with:
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
+ - uses: pnpm/action-setup@v2
+ with:
+ version: 9.3.0
+
- uses: actions/setup-node@v4
with:
node-version: 20
- cache: 'yarn'
+ cache: 'pnpm'
- - name: yarn
- run: yarn install
+ - name: pnpm
+ run: pnpm install
- name: Strip enterprise code
run: |
rm -rf enterprise
rm -rf spec/enterprise
+ - name: setup env
+ run: |
+ cp .env.example .env
+
- name: Run asset compile
run: bundle exec rake assets:precompile
env:
- NODE_OPTIONS: --openssl-legacy-provider
+ RAILS_ENV: production
- name: Size Check
- run: yarn run size
+ run: pnpm run size
+
+
diff --git a/.gitignore b/.gitignore
index 028a97f09..5eb883db0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,6 +32,16 @@ master.key
public/uploads
public/packs*
+public/assets/administrate*
+public/assets/action*.js
+public/assets/activestorage*.js
+public/assets/trix*
+public/assets/belongs_to*.js
+public/assets/manifest*.js
+public/assets/manifest*.js
+public/assets/*.js.gz
+public/assets/secretField*
+public/assets/.sprockets-manifest-*.json
# VIM files
*.swp
@@ -75,4 +85,8 @@ yalc.lock
yarn-debug.log*
.yarn-integrity
-/storybook-static
\ No newline at end of file
+# Vite Ruby
+/public/vite*
+# Vite uses dotenv and suggests to ignore local-only env files. See
+# https://vitejs.dev/guide/env-and-mode.html#env-files
+*.local
diff --git a/.husky/pre-commit b/.husky/pre-commit
index adda426ad..2525dde4e 100755
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -1,11 +1,11 @@
-#!/bin/sh
-. "$(dirname "$0")/_/husky.sh"
+# #!/bin/sh
+# . "$(dirname "$0")/_/husky.sh"
-# lint js and vue files
-npx --no-install lint-staged
+# # lint js and vue files
+# npx --no-install lint-staged
-# lint only staged ruby files
-git diff --name-only --cached | xargs ls -1 2>/dev/null | grep '\.rb$' | xargs bundle exec rubocop --force-exclusion -a
+# # lint only staged ruby files
+# git diff --name-only --cached | xargs ls -1 2>/dev/null | grep '\.rb$' | xargs bundle exec rubocop --force-exclusion -a
-# stage rubocop changes to files
-git diff --name-only --cached | xargs git add
+# # stage rubocop changes to files
+# git diff --name-only --cached | xargs git add
diff --git a/.storybook/main.js b/.storybook/main.js
deleted file mode 100644
index cb32634c2..000000000
--- a/.storybook/main.js
+++ /dev/null
@@ -1,56 +0,0 @@
-const path = require('path');
-const resolve = require('../config/webpack/resolve');
-
-// Chatwoot's webpack.config.js
-process.env.NODE_ENV = 'development';
-const custom = require('../config/webpack/environment');
-
-module.exports = {
- stories: [
- '../stories/**/*.stories.mdx',
- '../app/javascript/**/*.stories.@(js|jsx|ts|tsx)',
- ],
- addons: [
- {
- name: '@storybook/addon-docs',
- options: {
- vueDocgenOptions: {
- alias: {
- '@': path.resolve(__dirname, '../'),
- },
- },
- },
- },
- '@storybook/addon-links',
- '@storybook/addon-essentials',
- {
- /**
- * Fix Storybook issue with PostCSS@8
- * @see https://github.com/storybookjs/storybook/issues/12668#issuecomment-773958085
- */
- name: '@storybook/addon-postcss',
- options: {
- postcssLoaderOptions: {
- implementation: require('postcss'),
- },
- },
- },
- ],
- webpackFinal: config => {
- const newConfig = {
- ...config,
- resolve: {
- ...config.resolve,
- modules: custom.resolvedModules.map(i => i.value),
- },
- };
-
- newConfig.module.rules.push({
- test: /\.scss$/,
- use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'],
- include: path.resolve(__dirname, '../app/javascript'),
- });
-
- return newConfig;
- },
-};
diff --git a/.storybook/preview.js b/.storybook/preview.js
deleted file mode 100644
index 7c046d51a..000000000
--- a/.storybook/preview.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import { addDecorator } from '@storybook/vue';
-import Vue from 'vue';
-import Vuex from 'vuex';
-import VueI18n from 'vue-i18n';
-import Multiselect from 'vue-multiselect';
-import VueDOMPurifyHTML from 'vue-dompurify-html';
-import FluentIcon from 'shared/components/FluentIcon/DashboardIcon';
-
-import WootUiKit from '../app/javascript/dashboard/components';
-import i18n from '../app/javascript/dashboard/i18n';
-import { domPurifyConfig } from 'shared/helpers/HTMLSanitizer';
-
-import '../app/javascript/dashboard/assets/scss/storybook.scss';
-
-Vue.use(VueI18n);
-Vue.use(WootUiKit);
-Vue.use(Vuex);
-Vue.use(VueDOMPurifyHTML, domPurifyConfig);
-
-Vue.component('multiselect', Multiselect);
-Vue.component('fluent-icon', FluentIcon);
-
-const store = new Vuex.Store({});
-const i18nConfig = new VueI18n({
- locale: 'en',
- messages: i18n,
-});
-
-addDecorator(() => ({
- template: '
___
-# Chatwoot
+# Chatwoot
Customer engagement suite, an open-source alternative to Intercom, Zendesk, Salesforce Service Cloud etc.
@@ -98,7 +101,7 @@ Chatwoot now supports 1-Click deployment to DigitalOcean as a kubernetes app.
### Other deployment options
-For other supported options, checkout our [deployment page](https://chatwoot.com/deploy).
+For other supported options, checkout our [deployment page](https://chatwoot.com/deploy).
## Security
diff --git a/VERSION_CW b/VERSION_CW
index a5c4c7633..4eba2a62e 100644
--- a/VERSION_CW
+++ b/VERSION_CW
@@ -1 +1 @@
-3.9.0
+3.13.0
diff --git a/VERSION_CWCTL b/VERSION_CWCTL
index 834f26295..4a36342fc 100644
--- a/VERSION_CWCTL
+++ b/VERSION_CWCTL
@@ -1 +1 @@
-2.8.0
+3.0.0
diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js
index 2cc9549bc..00c9417ba 100644
--- a/app/assets/config/manifest.js
+++ b/app/assets/config/manifest.js
@@ -2,5 +2,4 @@
//= link administrate/application.css
//= link administrate/application.js
//= link administrate-field-active_storage/application.css
-//= link dashboardChart.js
//= link secretField.js
diff --git a/app/assets/javascripts/dashboardChart.js b/app/assets/javascripts/dashboardChart.js
deleted file mode 100644
index 46f278b80..000000000
--- a/app/assets/javascripts/dashboardChart.js
+++ /dev/null
@@ -1,55 +0,0 @@
-// eslint-disable-next-line
-function prepareData(data) {
- var labels = [];
- var dataSet = [];
- data.forEach(item => {
- labels.push(item[0]);
- dataSet.push(item[1]);
- });
- return { labels, dataSet };
-}
-
-function getChartOptions() {
- var fontFamily =
- 'PlusJakarta,-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif';
- return {
- responsive: true,
- legend: { labels: { fontFamily } },
- scales: {
- xAxes: [
- {
- barPercentage: 1.26,
- ticks: { fontFamily },
- gridLines: { display: false },
- },
- ],
- yAxes: [
- {
- ticks: { fontFamily },
- gridLines: { display: false },
- },
- ],
- },
- };
-}
-
-// eslint-disable-next-line
-function drawSuperAdminDashboard(data) {
- var ctx = document.getElementById('dashboard-chart').getContext('2d');
- var chartData = prepareData(data);
- // eslint-disable-next-line
- new Chart(ctx, {
- type: 'bar',
- data: {
- labels: chartData.labels,
- datasets: [
- {
- label: 'Conversations',
- data: chartData.dataSet,
- backgroundColor: '#1f93ff',
- },
- ],
- },
- options: getChartOptions(),
- });
-}
diff --git a/app/assets/stylesheets/administrate/utilities/_variables.scss b/app/assets/stylesheets/administrate/utilities/_variables.scss
index 3a1129c41..9123667e2 100644
--- a/app/assets/stylesheets/administrate/utilities/_variables.scss
+++ b/app/assets/stylesheets/administrate/utilities/_variables.scss
@@ -86,8 +86,5 @@ $swift-ease-out-duration: .4s !default;
$swift-ease-out-timing-function: cubic-bezier(.25, .8, .25, 1) !default;
$swift-ease-out: all $swift-ease-out-duration $swift-ease-out-timing-function !default;
-// Ionicons
-$ionicons-font-path: '~ionicons/fonts';
-
// Transitions
$transition-ease-in: all 0.250s ease-in;
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 332f1528f..6ddaab73b 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -72,7 +72,7 @@ class DashboardController < ActionController::Base
@application_pack = if request.path.include?('/auth') || request.path.include?('/login')
'v3app'
else
- 'application'
+ 'dashboard'
end
end
diff --git a/app/controllers/google/callbacks_controller.rb b/app/controllers/google/callbacks_controller.rb
index 391e1de0f..766d984df 100644
--- a/app/controllers/google/callbacks_controller.rb
+++ b/app/controllers/google/callbacks_controller.rb
@@ -1,6 +1,15 @@
class Google::CallbacksController < OauthCallbackController
include GoogleConcern
+ def find_channel_by_email
+ # find by imap_login first, and then by email
+ # this ensures the legacy users can migrate correctly even if inbox email address doesn't match
+ imap_channel = Channel::Email.find_by(imap_login: users_data['email'], account: account)
+ return imap_channel if imap_channel
+
+ Channel::Email.find_by(email: users_data['email'], account: account)
+ end
+
private
def provider_name
diff --git a/app/controllers/oauth_callback_controller.rb b/app/controllers/oauth_callback_controller.rb
index 309160f1f..4cb02d266 100644
--- a/app/controllers/oauth_callback_controller.rb
+++ b/app/controllers/oauth_callback_controller.rb
@@ -25,7 +25,7 @@ class OauthCallbackController < ApplicationController
end
def find_or_create_inbox
- channel_email = Channel::Email.find_by(email: users_data['email'], account: account)
+ channel_email = find_channel_by_email
# we need this value to know where to redirect on sucessful processing of the callback
channel_exists = channel_email.present?
@@ -39,6 +39,10 @@ class OauthCallbackController < ApplicationController
[channel_email.inbox, channel_exists]
end
+ def find_channel_by_email
+ Channel::Email.find_by(email: users_data['email'], account: account)
+ end
+
def update_channel(channel_email)
channel_email.update!({
imap_login: users_data['email'], imap_address: imap_address,
diff --git a/app/javascript/dashboard/App.vue b/app/javascript/dashboard/App.vue
index da169d61f..c32cb98d2 100644
--- a/app/javascript/dashboard/App.vue
+++ b/app/javascript/dashboard/App.vue
@@ -1,6 +1,5 @@
+
+
+
+ {{ subtitle }}
+
+ {{ description }}
+ Selected value: {{ selectedValue }}
+ {{ message }}
+
+ {{ title }}
+
+
+
+
diff --git a/app/javascript/dashboard/components-next/HelpCenter/Pages/ArticlePage/ArticlesPage.story.vue b/app/javascript/dashboard/components-next/HelpCenter/Pages/ArticlePage/ArticlesPage.story.vue
new file mode 100644
index 000000000..cfb353200
--- /dev/null
+++ b/app/javascript/dashboard/components-next/HelpCenter/Pages/ArticlePage/ArticlesPage.story.vue
@@ -0,0 +1,72 @@
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/components-next/HelpCenter/Pages/EditArticlePage/EditArticlePage.vue b/app/javascript/dashboard/components-next/HelpCenter/Pages/EditArticlePage/EditArticlePage.vue
new file mode 100644
index 000000000..2b1ea588e
--- /dev/null
+++ b/app/javascript/dashboard/components-next/HelpCenter/Pages/EditArticlePage/EditArticlePage.vue
@@ -0,0 +1,146 @@
+
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/components-next/HelpCenter/Pages/LocalePage/LocalesPage.story.vue b/app/javascript/dashboard/components-next/HelpCenter/Pages/LocalePage/LocalesPage.story.vue
new file mode 100644
index 000000000..630c50ca4
--- /dev/null
+++ b/app/javascript/dashboard/components-next/HelpCenter/Pages/LocalePage/LocalesPage.story.vue
@@ -0,0 +1,52 @@
+
+
+
+
+ Configuration
+
+
+ {{ header }}
+
+
+
+
+
{{ headerContent }}
diff --git a/app/javascript/dashboard/components/NetworkNotification.vue b/app/javascript/dashboard/components/NetworkNotification.vue
index 72e74e8a9..98149217e 100644
--- a/app/javascript/dashboard/components/NetworkNotification.vue
+++ b/app/javascript/dashboard/components/NetworkNotification.vue
@@ -1,7 +1,7 @@
+
+ {{ $t('REPORT.PAGINATION.RESULTS', { start, end, total }) }}
+
+
+
+
diff --git a/app/javascript/dashboard/components/ui/AnnouncementPopup.vue b/app/javascript/dashboard/components/ui/AnnouncementPopup.vue
index 5d49bc786..14f2c7d7d 100644
--- a/app/javascript/dashboard/components/ui/AnnouncementPopup.vue
+++ b/app/javascript/dashboard/components/ui/AnnouncementPopup.vue
@@ -18,6 +18,7 @@ export default {
default: '',
},
},
+ emits: ['open', 'close'],
methods: {
onClickOpenPath() {
this.$emit('open');
diff --git a/app/javascript/dashboard/components/ui/Banner.vue b/app/javascript/dashboard/components/ui/Banner.vue
index a4372149d..7071de61e 100644
--- a/app/javascript/dashboard/components/ui/Banner.vue
+++ b/app/javascript/dashboard/components/ui/Banner.vue
@@ -38,6 +38,7 @@ export default {
default: false,
},
},
+ emits: ['primaryAction', 'close'],
computed: {
bannerClasses() {
const classList = [this.colorScheme];
@@ -50,7 +51,7 @@ export default {
},
methods: {
onClick(e) {
- this.$emit('click', e);
+ this.$emit('primaryAction', e);
},
onClickClose(e) {
this.$emit('close', e);
@@ -61,7 +62,7 @@ export default {
+
+
+
+
+
+
+
+
+
+
+
+