Compare commits

...
Author SHA1 Message Date
Pranav Raj S 46b91ad840 Running version 2024-01-27 23:33:15 -08:00
Pranav Raj S ed8b58ad10 Remove foundation 2024-01-27 23:25:10 -08:00
Pranav Raj S 4928f28c64 Remove ionicons 2024-01-27 23:23:27 -08:00
Pranav Raj S 30539c27f2 Merge branch 'develop' into vite-ruby-migration 2024-01-27 23:21:44 -08:00
Pranav Raj SandGitHub 12916ceca6 fix: Capture delivery errors to avoid false positives (#8790)
The system did not detect the delivery errors earlier, resulting in some false positives. The user was not informed when an email failed to be delivered. While we do handle failure status in other channels, we were not able to capture the actual delivery status for the email channel.

This pull request makes the following changes:

- Updated the class EmailReplyWorker to use the deliver_now method instead of deliver_later. This change is made to raise any errors that may occur with the SMTP connection. The errors are then captured and sent to Sentry, and the email is marked as failed. Previously, we did not consider the case of retries in the email channel, so this feature is currently not functioning. So, I have disabled the retry option. We will address this in a follow-up ticket.
- Downgraded the net-smtp gem to version 0.3.4. This change is made to avoid an argument error when using XOAUTH2.

Fixes: https://linear.app/chatwoot/issue/CW-3032/argumenterror-wrong-authentication-type-xoauth2-argumenterror
2024-01-26 14:22:18 +04:00
Pranav Raj S 2e747e7fa6 Remove webpack 2024-01-25 12:43:39 -08:00
Pranav Raj S a1b6b0c06c Running dashboard, help center 2024-01-25 12:32:50 -08:00
Pranav Raj S 1fe3960285 Upgrade @vuelidate to 2.x 2024-01-25 12:15:21 -08:00
Pranav Raj S c33c844039 Initial Vite Commit 2024-01-25 11:56:22 -08:00
3c952e6a4a fix: change email conversation not found exception to log (#8785)
* fix: change email conversation not found exception to log

* chore: refactor reply_mailbox methods

---------

Co-authored-by: Sojan Jose <sojan@pepalo.com>
2024-01-25 22:36:02 +05:30
Sojan JoseandGitHub 59184122f7 fix: [Snyk] Security upgrade administrate from 0.19.0 to 0.20.1 (#8741)
-  Upgrade  administrate  gem to latest
- Update the `show` partial with changes from upstream
2024-01-25 17:33:21 +04:00
381423b1ae fix: Removed author section from public help center (#8767)
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2024-01-25 17:17:16 +05:30
Pranav Raj SandGitHub b7c9f779ad fix: Avoid processing reactions, ephemeral, request_welcome or unsupported messages (#8780)
Currently, we do not support reactions, ephemeral messages, or the request_welcome event for the WhatsApp channel. However, if this is the first event we receive in Chatwoot (i.e., there is no previous conversation or contact in Chatwoot), it will create a contact and a conversation without any messages. This confuses our customer, as it may appear that Chatwoot has missed some messages. There are multiple cases where this might be the first event we receive in Chatwoot. One quick example is when the user has sent an outbound campaign from another tool and their customers reacted to the message.

Another event like this is request_welcome event. WhatsApp has a concept for welcome messages. You can send an outbound message even though the user has not send a message. You can receive notifications through a webhook whenever a WhatsApp user initiates a chat with you for the first time. (Read the Welcome message section: https://developers.facebook.com/docs/whatsapp/cloud-api/phone-numbers/conversational-components/ ). Although this can help the business send a pro-active message to the user, we don't have it scoped in our feature set. For now, I'm ignoring this event.

Fixes https://linear.app/chatwoot/issue/CW-3018/whatsapp-handle-request-welcome-case-properly
Fixes https://linear.app/chatwoot/issue/CW-3017/whatsapp-handle-reactions-properly
2024-01-25 11:40:18 +04:00
Muhsin KelothandGitHub 904d76420d fix: Add last_activity_at to notification push event data (#8784)
fix: Add last_activity_at to push event data
2024-01-25 12:05:00 +05:30
Muhsin KelothandGitHub fa907840c7 feat: Add middle_name and last_name to contact model (#8771)
feat: Add `middle_name` and `last_name`
2024-01-24 16:22:04 +05:30
3760f206e8 fix: mutex timeout and error handling (#8770)
Fixes the follow cases 
- The ensure block released the lock even on LockAcquisitionError
- Custom timeout was not allowed

This also refactored the with_lock method, now the key has to be constructed in the parent function itself

Co-authored-by: Sojan Jose <sojan@pepalo.com>
2024-01-24 14:18:21 +04:00
Sojan JoseandGitHub a861257f73 chore: Fix flaky contacts spec (#8773)
- The ordering was not guaranteed; hence, the specs were failing randomly. Made changes to the expectations accordingly
2024-01-24 13:58:27 +04:00
Muhsin KelothandGitHub 143299f138 feat: Add contact_type attribute to contact model (#8768) 2024-01-24 12:26:47 +05:30
Vishnu NarayananandGitHub 232369cd5c feat: sla 1 - refactor sla_policies model and add applied_sla model (#8602)
* feat: add models

* chore: refactor sla column names

* chore: remove foreign keys

* chore: fix spec

* chore: refactor models
2024-01-23 23:48:02 +05:30
Surabhi SumanandGitHub 4b40c61201 feat: Support Regex validation for custom attributes (#7856)
This allows a user to add/update a custom regex and a cue while defining custom attributes(Only applicable for type- text).
While adding/editing custom attributes, the values are validated against the attribute definition regex, and if it is incorrect, a cue message or default error message is shown and restricts invalid values from being saved.

Fixes: #6866
2024-01-23 18:01:57 +04:00
834c219b9b feat(perf): update query to do a simpler search [CW-2997] (#8763)
Message search would frequently timeout. The reason was that the query would join the conversation too, the new query searches the message table directly

Co-authored-by: Sojan <sojan@pepalo.com>
2024-01-23 14:20:00 +04:00
Sivin VargheseandGitHub d0cd1c8887 fix: Help center articles not accessible after authoring agent is deleted (#8756) 2024-01-23 14:06:51 +05:30
Muhsin KelothandGitHub 682a2aea1c chore: Handle twillio Down::ClientError (#8757)
Fixes: https://linear.app/chatwoot/issue/CW-2992/downclienterror-400-bad-request-downclienterror
2024-01-22 15:33:26 +04:00
Shivam MishraandGitHub 1dc66db516 fix: SQL error when rules with missing attributes is triggered (#8673) 2024-01-22 16:09:34 +05:30
Sojan JoseandGitHub bc04d81a5a fix: Handle Net::IMAP::InvalidResponseError Exception bad response type "ESMTP" (#8755) 2024-01-22 15:32:44 +05:30
d2c5c2f9a3 chore: [Snyk] Security upgrade sidekiq from 7.2.0 to 7.2.1 (#8748)
Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2024-01-22 13:12:26 +04:00
Sojan JoseandGitHub 381fda270a chore: Fix typo in Inbox Management copy (#8750)
- Fixes the typo in Inbox Management copy -> vistors to visitors
2024-01-22 13:07:36 +04:00
b3c9d1f1a5 fix: clear timers and animation frame request before component unmounts (#8700)
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2024-01-22 12:08:33 +05:30
Sivin VargheseandGitHub fd4376d062 fix: TypeError: Cannot read properties of undefined (reading 'emoji') (#8753) 2024-01-22 12:06:59 +05:30
Pranav Raj SandGitHub a8f053921b fix: Migrate notes when merging the contacts (#8749)
Fixes: https://linear.app/chatwoot/issue/CW-2987/migrate-notes-of-the-secondary-contact-to-primary-contact-when-merging
2024-01-20 10:32:18 +04:00
Sivin VargheseandGitHub 8e15ada164 fix: TypeError: Cannot read properties of undefined (reading 'emoji') (#8747) 2024-01-19 19:55:51 +05:30
Sojan 51093fd543 Merge branch 'release/3.5.2' into develop 2024-01-19 15:15:33 +04:00
Sojan 48e638cc56 Bump version to 3.5.2 2024-01-19 15:14:49 +04:00
Pavel KuzminandGitHub e6dfc159ed fix: change teamid (#8613) 2024-01-19 16:15:28 +05:30
Chatwoot BotandGitHub 900c2de89a chore: Update translations (#8717) 2024-01-19 14:32:27 +04:00
29106ebc4b fix: raise_lock_acquisition_error if the job cannot set the lock (#8744)
Consider a scenario where two jobs are concurrently accessing a job with a lock mechanism. If the second job accesses lock_manager.locked? before the first job called lock_manager.lock(lock_key), it would return a false positive. At this point, both jobs can be executed freely.

To address this issue, the following change ensures that only the current thread that has set the lock can execute. Otherwise, a LockAcquisitionError will be thrown.

Co-authored-by: Sojan Jose <sojan@pepalo.com>
Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
2024-01-19 14:31:41 +04:00
Pranav Raj SandGitHub a579684b34 fix: Update the message-id check to use messageId parsing from mail gem (#8743)
- Update the message ID parsing logic to use the mail gem
- Update the code to improve readability
2024-01-19 14:29:04 +04:00
c29a9ad062 feat: Updates branding logo and name in public portal footer (#8745)
- Use white-label settings for Chatwoot Help Center

Co-authored-by: Sojan <sojan@pepalo.com>
2024-01-19 13:37:24 +04:00
Muhsin KelothandGitHub 0ac015ce7a feat: Add a job to clear notifications that were created before 1 month (#8732) 2024-01-19 13:03:23 +05:30
19474e0074 chore: Improve active job error logs for deserialization error (#8742)
- Improve active job error logs for deserialization error 

Co-authored-by: Sojan <sojan@pepalo.com>
2024-01-18 19:27:18 +04:00
Sojan JoseandGitHub ce8190dacf fix: API error when using SuperAdmin token (#8739)
- Fixes the issue in release 3.5.0, which causes SuperAdmin tokens to throw error during API calls

Fixes: #8719
2024-01-18 18:49:32 +04:00
Shivam MishraandGitHub aacf326ca1 refactor: remove exception tracker (#8737) 2024-01-18 17:49:27 +05:30
Shivam MishraandGitHub e39c14460b fix: validate url for Dashboard Apps [CW-2979] (#8736) 2024-01-18 17:48:30 +05:30
Sojan JoseandGitHub 5f6e17f307 feat: Use Telegram HTML Parsemode (#8731)
- this ensures that the markdown formatted messages from the Chatwoot dashboard will render consistently in telegram UI for the supported types like bold, italics, links etc
2024-01-18 15:36:36 +04:00
Shivam MishraandGitHub 4bf23adcf5 feat: use short_summary for downloading reports [CW-2962] (#8733) 2024-01-18 16:06:13 +05:30
Pranav Raj SandGitHub 1f4d860d9d fix: Use channel.inbox instead of inbox (#8734) 2024-01-18 00:46:25 -08:00
fdbb3bf4b1 fix: Optimize email fetching logic to fix bandwidth exceeded issues (#8730)
The Inboxes::FetchImapEmailsJob is designed to fetch the entire email object and check if its message id is already in the database. However, this process is resource-intensive and time-consuming, as fetching the full email object takes a significant amount of time.

On average, fetching 100 emails can take approximately 3-4 minutes to complete depending on the IMAP server. Since we are not using server flags to identify which emails have already been fetched (to avoid compatibility issues with flags in different email services), we have to fetch all previously available emails. Currently we fetch all the messages that were created from yesterday. This becomes problematic with services like Gmail, which throttle requests based on bandwidth usage.

To address this issue, I have updated the logic as follows:

Fetch the sequence IDs of all the mails in the "Inbox" that were created from yesterday.
Use the FETCH command to fetch only the message-ids using BODY.PEEK[HEADER.FIELDS (MESSAGE-ID)] with the sequence IDs we got in the previous step. This is a faster operation with lower bandwidth usage, as it only returns the sequence ID and message ID.
Check if the message IDs are already present in the database for the selected inbox.
If not present, fetch the entire email object using the FETCH command and create the message.
If the message ID is already present, ignore it and move on to the next message-id.
I have also addressed the issue of duplicate emails appearing in conversations when two fetch email jobs occur simultaneously. I have added a lock for the channel to ensure that the job gracefully exits without waiting for the current job to complete.

Fixes #7247
Fixes #6082
Fixes #8314

Co-authored-by: Sojan <sojan@pepalo.com>
2024-01-18 11:45:16 +04:00
Muhsin KelothandGitHub c899cc825d fix: Handle Contact import MalformedCSVError (#8706) 2024-01-18 13:05:58 +05:30
Muhsin KelothandGitHub eb972684b3 feat: Show notification last active time instead of created time (#8724) 2024-01-18 09:41:53 +05:30
Muhsin KelothandGitHub 896473f03e fix: Notification count is incorrect when the number of notifications exceeds the page size. (#8723)
- The notification count is incorrect when the number of notifications exceeds the page size.
2024-01-17 15:14:37 +04:00
Sojan 8c43edbd50 Merge branch 'release/3.5.1' into develop 2024-01-17 13:48:28 +04:00
Sojan 4c4eb4bd90 Bump version to 3.5.1 2024-01-17 13:47:57 +04:00
Vishnu NarayananandGitHub 88b8597e4d chore: log emails sent from chatwoot (#8721)
- Log details related to emails sent from Chatwoot to assist in debugging email delivery/bounces/complaints
2024-01-17 13:19:14 +04:00
Sojan JoseandGitHub 76fe2f9bb8 chore: Switch to Markdown instead of MarkdownV2 for telegram channel (#8720) 2024-01-17 14:28:13 +05:30
818424259f chore: Get all notification API improvments (#8549)
Co-authored-by: Sojan Jose <sojan@chatwoot.com>
2024-01-17 09:02:18 +05:30
Sivin VargheseandGitHub e67f8824d9 fix: Backdrop color for insert article modal in dark mode (#8711) 2024-01-16 18:36:43 +05:30
Sojan JoseandGitHub 8f1a1e0905 fix: Stop overwritting contact avatars unneccesarily (#8710)
While debugging a sentry error for "ActiveRecord::InvalidForeignKey ActiveStorage::Representations::RedirectController", it was noticed that we enqueue a Avatar::AvatarFromUrlJob for each setUser call, which is unnecessary. Hence making this call only if the contact doesn't have an existing avatar.

If one needs to have this avatar updated, they can go to the contacts tab and delete the current avatar, Chatwoot will pick up the new avatar in subsequent API call.
2024-01-16 16:38:46 +04:00
Mongkon KaenjanandGitHub 1b6360d9d3 chore: change OFFLINE text in th translations (#8642)
change OFFLINE text from เราไม่อยู่ to ออฟไลน์
2024-01-16 15:18:59 +04:00
8b7f10fe61 feat: log errors on automation filter (#8702)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2024-01-16 16:13:57 +05:30
4958b3e7b6 chore: Fix codespaces not booting up (#8264)
Fixed an issue where the codespace was not correctly booting up.
Fixes #7609

Co-authored-by: Liam Ashdown <liam.ashdown@debbiesvillas.co.uk>
Co-authored-by: Sojan <sojan@pepalo.com>
2024-01-16 14:34:23 +04:00
e467d15f2c chore: Update translations (#8544)
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2024-01-16 13:49:38 +04:00
d1e7e75638 feat: Adds internal support for markdown in Telegram outgoing messages (#8640)
This PR adds support for Markdown in the telegram API for send message. The dashboard uses commonmark syntax for markdown but telegram is using MarkdownV2.
More info - https://core.telegram.org/bots/api#markdownv2-style

Adds support for bold - *bold*, _italic text_, __underline__, ~strikethrough~

Co-authored-by: Sojan Jose <sojan@pepalo.com>
2024-01-16 13:32:59 +04:00
Sojan 4aab63b7df Merge branch 'release/3.5.0' into develop 2024-01-16 11:15:29 +04:00
810 changed files with 13781 additions and 22459 deletions
+1 -1
View File
@@ -74,7 +74,7 @@ jobs:
name: yarn name: yarn
command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
# Store yarn / webpacker cache # Store yarn cache
- save_cache: - save_cache:
key: chatwoot-yarn-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }} key: chatwoot-yarn-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }}
paths: paths:
+1 -1
View File
@@ -2,7 +2,7 @@
# It has the dependencies already installed so that codespace will boot up fast # It has the dependencies already installed so that codespace will boot up fast
FROM ghcr.io/chatwoot/chatwoot_codespace:latest FROM ghcr.io/chatwoot/chatwoot_codespace:latest
# Do the set up required for chatwoot app # Do the set up required for chatwoot app
WORKDIR /workspace WORKDIR /workspace
COPY . /workspace COPY . /workspace
RUN yarn && gem install bundler && bundle install RUN yarn && gem install bundler && bundle install
+14 -11
View File
@@ -1,10 +1,14 @@
ARG VARIANT=ubuntu-20.04 ARG VARIANT
FROM mcr.microsoft.com/vscode/devcontainers/base:${VARIANT}
FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT}
ARG NODE_VERSION
ARG RUBY_VERSION
ARG USER_UID
ARG USER_GID
# Update args in docker-compose.yaml to set the UID/GID of the "vscode" user. # Update args in docker-compose.yaml to set the UID/GID of the "vscode" user.
ARG USER_UID=1000
ARG USER_GID=$USER_UID
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \ RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
groupmod --gid $USER_GID vscode \ groupmod --gid $USER_GID vscode \
&& usermod --uid $USER_UID --gid $USER_GID vscode \ && usermod --uid $USER_UID --gid $USER_GID vscode \
@@ -27,10 +31,10 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
tmux \ tmux \
zsh \ zsh \
git-flow \ git-flow \
npm npm \
libyaml-dev
# Install rbenv and ruby # Install rbenv and ruby
ARG RUBY_VERSION="3.2.2"
RUN git clone https://github.com/rbenv/rbenv.git ~/.rbenv \ RUN git clone https://github.com/rbenv/rbenv.git ~/.rbenv \
&& echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc \ && echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc \
&& echo 'eval "$(rbenv init -)"' >> ~/.bashrc && echo 'eval "$(rbenv init -)"' >> ~/.bashrc
@@ -46,7 +50,7 @@ RUN rbenv install $RUBY_VERSION && \
RUN curl -L https://github.com/DarthSim/overmind/releases/download/v2.1.0/overmind-v2.1.0-linux-amd64.gz > overmind.gz \ RUN curl -L https://github.com/DarthSim/overmind/releases/download/v2.1.0/overmind-v2.1.0-linux-amd64.gz > overmind.gz \
&& gunzip overmind.gz \ && gunzip overmind.gz \
&& sudo mv overmind /usr/local/bin \ && sudo mv overmind /usr/local/bin \
&& chmod +x /usr/local/bin/overmind && chmod +x /usr/local/bin/overmind
# Install gh # Install gh
@@ -56,7 +60,7 @@ RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | s
&& sudo apt install gh && sudo apt install gh
# Do the set up required for chatwoot app # Do the set up required for chatwoot app
WORKDIR /workspace WORKDIR /workspace
COPY . /workspace COPY . /workspace
@@ -65,8 +69,7 @@ COPY Gemfile Gemfile.lock ./
RUN gem install bundler && bundle install RUN gem install bundler && bundle install
# set up node js # set up node js
RUN npm install npm@latest -g && \ RUN npm install n -g && \
npm install n -g && \ n $NODE_VERSION
n latest
RUN npm install --global yarn RUN npm install --global yarn
RUN yarn RUN yarn
+23 -13
View File
@@ -1,30 +1,41 @@
# https://github.com/microsoft/vscode-dev-containers/blob/master/containers/python-3-postgres/.devcontainer/docker-compose.yml # https://github.com/microsoft/vscode-dev-containers/blob/master/containers/python-3-postgres/.devcontainer/docker-compose.yml
# https://github.com/microsoft/vscode-dev-containers/blob/master/containers/ruby-rails/.devcontainer/devcontainer.json # https://github.com/microsoft/vscode-dev-containers/blob/master/containers/ruby-rails/.devcontainer/devcontainer.json
# #
version: '3' version: '3'
services: services:
app: base:
build:
context: ..
dockerfile: .devcontainer/Dockerfile.base
args:
VARIANT: "ubuntu-22.04"
NODE_VERSION: "20.9.0"
RUBY_VERSION: "3.2.2"
# On Linux, you may need to update USER_UID and USER_GID below if not your local UID is not 1000.
USER_UID: "1000"
USER_GID: "1000"
image: base:latest
app:
build: build:
context: .. context: ..
dockerfile: .devcontainer/Dockerfile dockerfile: .devcontainer/Dockerfile
args: args:
# Update 'VARIANT' to pick a Ruby version: https://github.com/microsoft/vscode-dev-containers/tree/main/containers/ruby VARIANT: "ubuntu-22.04"
VARIANT: 3 NODE_VERSION: "20.9.0"
# [Choice] Install Node.js RUBY_VERSION: "3.2.2"
INSTALL_NODE: "true"
NODE_VERSION: "lts/*"
# On Linux, you may need to update USER_UID and USER_GID below if not your local UID is not 1000. # On Linux, you may need to update USER_UID and USER_GID below if not your local UID is not 1000.
USER_UID: 1000 USER_UID: "1000"
USER_GID: 1000 USER_GID: "1000"
volumes: volumes:
- ..:/workspace:cached - ..:/workspace:cached
# Overrides default command so things don't shut down after the process ends. # Overrides default command so things don't shut down after the process ends.
command: sleep infinity command: sleep infinity
# Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function. # Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
network_mode: service:db network_mode: service:db
@@ -49,8 +60,7 @@ services:
restart: unless-stopped restart: unless-stopped
image: mailhog/mailhog image: mailhog/mailhog
network_mode: service:db network_mode: service:db
volumes: volumes:
postgres-data: postgres-data:
redis-data: redis-data:
+4 -4
View File
@@ -3,10 +3,10 @@ sed -i -e '/REDIS_URL/ s/=.*/=redis:\/\/localhost:6379/' .env
sed -i -e '/POSTGRES_HOST/ s/=.*/=localhost/' .env sed -i -e '/POSTGRES_HOST/ s/=.*/=localhost/' .env
sed -i -e '/SMTP_ADDRESS/ s/=.*/=localhost/' .env sed -i -e '/SMTP_ADDRESS/ s/=.*/=localhost/' .env
sed -i -e "/FRONTEND_URL/ s/=.*/=https:\/\/$CODESPACE_NAME-3000.githubpreview.dev/" .env sed -i -e "/FRONTEND_URL/ s/=.*/=https:\/\/$CODESPACE_NAME-3000.githubpreview.dev/" .env
sed -i -e "/WEBPACKER_DEV_SERVER_PUBLIC/ s/=.*/=https:\/\/$CODESPACE_NAME-3035.githubpreview.dev/" .env sed -i -e "/DEV_SERVER_PUBLIC/ s/=.*/=https:\/\/$CODESPACE_NAME-3035.githubpreview.dev/" .env
# uncomment the webpacker env variable # uncomment the dev server env variable
sed -i -e '/WEBPACKER_DEV_SERVER_PUBLIC/s/^# //' .env sed -i -e '/DEV_SERVER_PUBLIC/s/^# //' .env
# fix the error with webpacker # fix the error with dev server
echo 'export NODE_OPTIONS=--openssl-legacy-provider' >> ~/.zshrc echo 'export NODE_OPTIONS=--openssl-legacy-provider' >> ~/.zshrc
# codespaces make the ports public # codespaces make the ports public
+1 -1
View File
@@ -223,7 +223,7 @@ ANDROID_SHA256_CERT_FINGERPRINT=AC:73:8E:DE:EB:56:EA:CC:10:87:02:A7:65:37:7B:38:
# if you want to use letter_opener for local emails # if you want to use letter_opener for local emails
# LETTER_OPENER=true # LETTER_OPENER=true
# meant to be used in github codespaces # meant to be used in github codespaces
# WEBPACKER_DEV_SERVER_PUBLIC= # DEV_SERVER_PUBLIC=
# If you want to use official mobile app, # If you want to use official mobile app,
# the notifications would be relayed via a Chatwoot server # the notifications would be relayed via a Chatwoot server
+2 -10
View File
@@ -7,11 +7,10 @@ module.exports = {
'plugin:cypress/recommended', 'plugin:cypress/recommended',
], ],
parserOptions: { parserOptions: {
parser: '@babel/eslint-parser', ecmaVersion: 2022,
ecmaVersion: 2020,
sourceType: 'module', sourceType: 'module',
}, },
plugins: ['html', 'prettier', 'babel'], plugins: ['html', 'prettier'],
rules: { rules: {
'prettier/prettier': ['error'], 'prettier/prettier': ['error'],
camelcase: 'off', camelcase: 'off',
@@ -56,13 +55,6 @@ module.exports = {
'import/extensions': ['off'], 'import/extensions': ['off'],
'no-console': 'error', 'no-console': 'error',
}, },
settings: {
'import/resolver': {
webpack: {
config: 'config/webpack/resolve.js',
},
},
},
env: { env: {
browser: true, browser: true,
jest: true, jest: true,
@@ -19,5 +19,6 @@ jobs:
- name: Build the Codespace Base Image - name: Build the Codespace Base Image
run: | run: |
docker build . -t ghcr.io/chatwoot/chatwoot_codespace:latest -f .devcontainer/Dockerfile.base docker-compose -f .devcontainer/docker-compose.yml build base
docker tag base:latest ghcr.io/chatwoot/chatwoot_codespace:latest
docker push ghcr.io/chatwoot/chatwoot_codespace:latest docker push ghcr.io/chatwoot/chatwoot_codespace:latest
+9 -1
View File
@@ -75,4 +75,12 @@ yalc.lock
yarn-debug.log* yarn-debug.log*
.yarn-integrity .yarn-integrity
/storybook-static /storybook-static
# Vite Ruby
/public/vite*
node_modules
# Vite uses dotenv and suggests to ignore local-only env files. See
# https://vitejs.dev/guide/env-and-mode.html#env-files
*.local
+1 -3
View File
@@ -2,7 +2,6 @@ import { addDecorator } from '@storybook/vue';
import Vue from 'vue'; import Vue from 'vue';
import Vuex from 'vuex'; import Vuex from 'vuex';
import VueI18n from 'vue-i18n'; import VueI18n from 'vue-i18n';
import Vuelidate from 'vuelidate';
import Multiselect from 'vue-multiselect'; import Multiselect from 'vue-multiselect';
import VueDOMPurifyHTML from 'vue-dompurify-html'; import VueDOMPurifyHTML from 'vue-dompurify-html';
import FluentIcon from 'shared/components/FluentIcon/DashboardIcon'; import FluentIcon from 'shared/components/FluentIcon/DashboardIcon';
@@ -14,7 +13,6 @@ import { domPurifyConfig } from 'shared/helpers/HTMLSanitizer';
import '../app/javascript/dashboard/assets/scss/storybook.scss'; import '../app/javascript/dashboard/assets/scss/storybook.scss';
Vue.use(VueI18n); Vue.use(VueI18n);
Vue.use(Vuelidate);
Vue.use(WootUiKit); Vue.use(WootUiKit);
Vue.use(Vuex); Vue.use(Vuex);
Vue.use(VueDOMPurifyHTML, domPurifyConfig); Vue.use(VueDOMPurifyHTML, domPurifyConfig);
@@ -32,7 +30,7 @@ addDecorator(() => ({
template: '<story/>', template: '<story/>',
i18n: i18nConfig, i18n: i18nConfig,
store, store,
beforeCreate: function() { beforeCreate: function () {
this.$root._i18n = this.$i18n; this.$root._i18n = this.$i18n;
}, },
})); }));
+5 -3
View File
@@ -39,6 +39,8 @@ gem 'rack-attack', '>= 6.7.0'
gem 'down' gem 'down'
# authentication type to fetch and send mail over oauth2.0 # authentication type to fetch and send mail over oauth2.0
gem 'gmail_xoauth' gem 'gmail_xoauth'
# Lock net-smtp to 0.3.4 to avoid issues with gmail_xoauth2
gem 'net-smtp', '~> 0.3.4'
# Prevent CSV injection # Prevent CSV injection
gem 'csv-safe' gem 'csv-safe'
@@ -62,7 +64,7 @@ gem 'activerecord-import'
gem 'dotenv-rails' gem 'dotenv-rails'
gem 'foreman' gem 'foreman'
gem 'puma' gem 'puma'
gem 'webpacker' gem 'vite_rails'
# metrics on heroku # metrics on heroku
gem 'barnes' gem 'barnes'
@@ -74,7 +76,7 @@ gem 'devise_token_auth'
gem 'jwt' gem 'jwt'
gem 'pundit' gem 'pundit'
# super admin # super admin
gem 'administrate', '>= 0.19.0' gem 'administrate', '>= 0.20.1'
gem 'administrate-field-active_storage', '>= 1.0.1' gem 'administrate-field-active_storage', '>= 1.0.1'
gem 'administrate-field-belongs_to_search', '>= 0.9.0' gem 'administrate-field-belongs_to_search', '>= 0.9.0'
@@ -114,7 +116,7 @@ gem 'sentry-ruby', require: false
gem 'sentry-sidekiq', '>= 5.14.0', require: false gem 'sentry-sidekiq', '>= 5.14.0', require: false
##-- background job processing --## ##-- background job processing --##
gem 'sidekiq', '>= 7.1.3' gem 'sidekiq', '>= 7.2.1'
# We want cron jobs # We want cron jobs
gem 'sidekiq-cron', '>= 1.12.0' gem 'sidekiq-cron', '>= 1.12.0'
+25 -22
View File
@@ -105,12 +105,12 @@ GEM
activerecord (>= 6.0, < 7.1) activerecord (>= 6.0, < 7.1)
addressable (2.8.4) addressable (2.8.4)
public_suffix (>= 2.0.2, < 6.0) public_suffix (>= 2.0.2, < 6.0)
administrate (0.19.0) administrate (0.20.1)
actionpack (>= 5.0) actionpack (>= 6.0, < 8.0)
actionview (>= 5.0) actionview (>= 6.0, < 8.0)
activerecord (>= 5.0) activerecord (>= 6.0, < 8.0)
jquery-rails (>= 4.0) jquery-rails (~> 4.6.0)
kaminari (>= 1.0) kaminari (~> 1.2.2)
sassc-rails (~> 2.1) sassc-rails (~> 2.1)
selectize-rails (~> 0.6) selectize-rails (~> 0.6)
administrate-field-active_storage (1.0.1) administrate-field-active_storage (1.0.1)
@@ -169,7 +169,7 @@ GEM
climate_control (1.2.0) climate_control (1.2.0)
coderay (1.1.3) coderay (1.1.3)
commonmarker (0.23.10) commonmarker (0.23.10)
concurrent-ruby (1.2.2) concurrent-ruby (1.2.3)
connection_pool (2.4.1) connection_pool (2.4.1)
crack (0.4.5) crack (0.4.5)
rexml rexml
@@ -216,6 +216,7 @@ GEM
railties (>= 3.2) railties (>= 3.2)
down (5.4.0) down (5.4.0)
addressable (~> 2.8) addressable (~> 2.8)
dry-cli (1.0.0)
ecma-re-validator (0.4.0) ecma-re-validator (0.4.0)
regexp_parser (~> 2.2) regexp_parser (~> 2.2)
elastic-apm (4.6.2) elastic-apm (4.6.2)
@@ -461,7 +462,7 @@ GEM
mini_magick (4.12.0) mini_magick (4.12.0)
mini_mime (1.1.5) mini_mime (1.1.5)
mini_portile2 (2.8.5) mini_portile2 (2.8.5)
minitest (5.20.0) minitest (5.21.2)
mock_redis (0.36.0) mock_redis (0.36.0)
ruby2_keywords ruby2_keywords
msgpack (1.7.0) msgpack (1.7.0)
@@ -479,7 +480,7 @@ GEM
net-protocol net-protocol
net-protocol (0.2.2) net-protocol (0.2.2)
timeout timeout
net-smtp (0.4.0) net-smtp (0.3.4)
net-protocol net-protocol
netrc (0.11.0) netrc (0.11.0)
newrelic-sidekiq-metrics (1.6.2) newrelic-sidekiq-metrics (1.6.2)
@@ -570,7 +571,7 @@ GEM
rack (>= 1.2.0) rack (>= 1.2.0)
rack-protection (3.1.0) rack-protection (3.1.0)
rack (~> 2.2, >= 2.2.4) rack (~> 2.2, >= 2.2.4)
rack-proxy (0.7.6) rack-proxy (0.7.7)
rack rack
rack-test (2.1.0) rack-test (2.1.0)
rack (>= 1.3) rack (>= 1.3)
@@ -610,7 +611,7 @@ GEM
ffi (~> 1.0) ffi (~> 1.0)
redis (5.0.6) redis (5.0.6)
redis-client (>= 0.9.0) redis-client (>= 0.9.0)
redis-client (0.19.0) redis-client (0.19.1)
connection_pool connection_pool
redis-namespace (1.10.0) redis-namespace (1.10.0)
redis (>= 4) redis (>= 4)
@@ -708,7 +709,6 @@ GEM
activerecord (>= 4) activerecord (>= 4)
activesupport (>= 4) activesupport (>= 4)
selectize-rails (0.12.6) selectize-rails (0.12.6)
semantic_range (3.0.0)
sentry-rails (5.14.0) sentry-rails (5.14.0)
railties (>= 5.0) railties (>= 5.0)
sentry-ruby (~> 5.14.0) sentry-ruby (~> 5.14.0)
@@ -720,11 +720,11 @@ GEM
sexp_processor (4.17.0) sexp_processor (4.17.0)
shoulda-matchers (5.3.0) shoulda-matchers (5.3.0)
activesupport (>= 5.2.0) activesupport (>= 5.2.0)
sidekiq (7.2.0) sidekiq (7.2.1)
concurrent-ruby (< 2) concurrent-ruby (< 2)
connection_pool (>= 2.3.0) connection_pool (>= 2.3.0)
rack (>= 2.2.4) rack (>= 2.2.4)
redis-client (>= 0.14.0) redis-client (>= 0.19.0)
sidekiq-cron (1.12.0) sidekiq-cron (1.12.0)
fugit (~> 1.8) fugit (~> 1.8)
globalid (>= 1.0.1) globalid (>= 1.0.1)
@@ -795,6 +795,13 @@ GEM
activemodel (>= 3.2) activemodel (>= 3.2)
mail (~> 2.5) mail (~> 2.5)
version_gem (1.1.2) version_gem (1.1.2)
vite_rails (3.0.17)
railties (>= 5.1, < 8)
vite_ruby (~> 3.0, >= 3.2.2)
vite_ruby (3.5.0)
dry-cli (>= 0.7, < 2)
rack-proxy (~> 0.6, >= 0.6.1)
zeitwerk (~> 2.2)
warden (1.2.9) warden (1.2.9)
rack (>= 2.0.9) rack (>= 2.0.9)
web-console (4.2.1) web-console (4.2.1)
@@ -810,11 +817,6 @@ GEM
addressable (>= 2.8.0) addressable (>= 2.8.0)
crack (>= 0.3.2) crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0) hashdiff (>= 0.4.0, < 2.0.0)
webpacker (5.4.4)
activesupport (>= 5.2)
rack-proxy (>= 0.6.1)
railties (>= 5.2)
semantic_range (>= 2.3.0)
webrick (1.8.1) webrick (1.8.1)
websocket-driver (0.7.6) websocket-driver (0.7.6)
websocket-extensions (>= 0.1.0) websocket-extensions (>= 0.1.0)
@@ -840,7 +842,7 @@ DEPENDENCIES
active_record_query_trace active_record_query_trace
activerecord-import activerecord-import
acts-as-taggable-on acts-as-taggable-on
administrate (>= 0.19.0) administrate (>= 0.20.1)
administrate-field-active_storage (>= 1.0.1) administrate-field-active_storage (>= 1.0.1)
administrate-field-belongs_to_search (>= 0.9.0) administrate-field-belongs_to_search (>= 0.9.0)
annotate annotate
@@ -903,6 +905,7 @@ DEPENDENCIES
meta_request meta_request
mock_redis mock_redis
neighbor neighbor
net-smtp (~> 0.3.4)
newrelic-sidekiq-metrics (>= 1.6.2) newrelic-sidekiq-metrics (>= 1.6.2)
newrelic_rpm newrelic_rpm
omniauth (>= 2.1.2) omniauth (>= 2.1.2)
@@ -939,7 +942,7 @@ DEPENDENCIES
sentry-ruby sentry-ruby
sentry-sidekiq (>= 5.14.0) sentry-sidekiq (>= 5.14.0)
shoulda-matchers shoulda-matchers
sidekiq (>= 7.1.3) sidekiq (>= 7.2.1)
sidekiq-cron (>= 1.12.0) sidekiq-cron (>= 1.12.0)
simplecov (= 0.17.1) simplecov (= 0.17.1)
slack-ruby-client (~> 2.2.0) slack-ruby-client (~> 2.2.0)
@@ -956,10 +959,10 @@ DEPENDENCIES
tzinfo-data tzinfo-data
uglifier uglifier
valid_email2 valid_email2
vite_rails
web-console (>= 4.2.1) web-console (>= 4.2.1)
web-push web-push
webmock webmock
webpacker
wisper (= 2.0.0) wisper (= 2.0.0)
working_hours working_hours
+1 -1
View File
@@ -1,4 +1,4 @@
backend: bin/rails s -p 3000 backend: bin/rails s -p 3000
frontend: export NODE_OPTIONS=--openssl-legacy-provider && bin/webpack-dev-server
# https://github.com/mperham/sidekiq/issues/3090#issuecomment-389748695 # https://github.com/mperham/sidekiq/issues/3090#issuecomment-389748695
worker: dotenv bundle exec sidekiq -C config/sidekiq.yml worker: dotenv bundle exec sidekiq -C config/sidekiq.yml
frontend: bin/vite dev
+1 -1
View File
@@ -1,3 +1,3 @@
backend: RAILS_ENV=test bin/rails s -p 5050 backend: RAILS_ENV=test bin/rails s -p 5050
frontend: export NODE_OPTIONS=--openssl-legacy-provider && bin/webpack-dev-server frontend: bin/vite
worker: RAILS_ENV=test dotenv bundle exec sidekiq -C config/sidekiq.yml worker: RAILS_ENV=test dotenv bundle exec sidekiq -C config/sidekiq.yml
+1 -1
View File
@@ -104,7 +104,7 @@ class ContactIdentifyAction
# TODO: replace reject { |_k, v| v.blank? } with compact_blank when rails is upgraded # TODO: replace reject { |_k, v| v.blank? } with compact_blank when rails is upgraded
@contact.discard_invalid_attrs if discard_invalid_attrs @contact.discard_invalid_attrs if discard_invalid_attrs
@contact.save! @contact.save!
Avatar::AvatarFromUrlJob.perform_later(@contact, params[:avatar_url]) if params[:avatar_url].present? Avatar::AvatarFromUrlJob.perform_later(@contact, params[:avatar_url]) if params[:avatar_url].present? && !@contact.avatar.attached?
end end
def merge_contact(base_contact, merge_contact) def merge_contact(base_contact, merge_contact)
+5
View File
@@ -12,6 +12,7 @@ class ContactMergeAction
merge_conversations merge_conversations
merge_messages merge_messages
merge_contact_inboxes merge_contact_inboxes
merge_contact_notes
merge_and_remove_mergee_contact merge_and_remove_mergee_contact
end end
@base_contact @base_contact
@@ -33,6 +34,10 @@ class ContactMergeAction
Conversation.where(contact_id: @mergee_contact.id).update(contact_id: @base_contact.id) Conversation.where(contact_id: @mergee_contact.id).update(contact_id: @base_contact.id)
end end
def merge_contact_notes
Note.where(contact_id: @mergee_contact.id, account_id: @mergee_contact.account_id).update(contact_id: @base_contact.id)
end
def merge_messages def merge_messages
Message.where(sender: @mergee_contact).update(sender: @base_contact) Message.where(sender: @mergee_contact).update(sender: @base_contact)
end end
@@ -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-timing-function: cubic-bezier(.25, .8, .25, 1) !default;
$swift-ease-out: all $swift-ease-out-duration $swift-ease-out-timing-function !default; $swift-ease-out: all $swift-ease-out-duration $swift-ease-out-timing-function !default;
// Ionicons
$ionicons-font-path: '~ionicons/fonts';
// Transitions // Transitions
$transition-ease-in: all 0.250s ease-in; $transition-ease-in: all 0.250s ease-in;
+4 -3
View File
@@ -2,8 +2,6 @@ class NotificationBuilder
pattr_initialize [:notification_type!, :user!, :account!, :primary_actor!, :secondary_actor] pattr_initialize [:notification_type!, :user!, :account!, :primary_actor!, :secondary_actor]
def perform def perform
return unless user_subscribed_to_notification?
build_notification build_notification
end end
@@ -16,7 +14,7 @@ class NotificationBuilder
def user_subscribed_to_notification? def user_subscribed_to_notification?
notification_setting = user.notification_settings.find_by(account_id: account.id) notification_setting = user.notification_settings.find_by(account_id: account.id)
# added for the case where an assignee might be removed from the account but remains in conversation # added for the case where an assignee might be removed from the account but remains in conversation
return if notification_setting.blank? return false if notification_setting.blank?
return true if notification_setting.public_send("email_#{notification_type}?") return true if notification_setting.public_send("email_#{notification_type}?")
return true if notification_setting.public_send("push_#{notification_type}?") return true if notification_setting.public_send("push_#{notification_type}?")
@@ -25,6 +23,9 @@ class NotificationBuilder
end end
def build_notification def build_notification
# Create conversation_creation notification only if user is subscribed to it
return if notification_type == 'conversation_creation' && !user_subscribed_to_notification?
user.notifications.create!( user.notifications.create!(
notification_type: notification_type, notification_type: notification_type,
account: account, account: account,
+8
View File
@@ -46,6 +46,14 @@ class V2::ReportBuilder
} }
end end
def short_summary
{
conversations_count: conversations.count,
avg_first_response_time: avg_first_response_time_summary,
avg_resolution_time: avg_resolution_time_summary
}
end
def conversation_metrics def conversation_metrics
if params[:type].equal?(:account) if params[:type].equal?(:account)
live_conversations live_conversations
@@ -39,6 +39,8 @@ class Api::V1::Accounts::CustomAttributeDefinitionsController < Api::V1::Account
:attribute_display_type, :attribute_display_type,
:attribute_key, :attribute_key,
:attribute_model, :attribute_model,
:regex_pattern,
:regex_cue,
attribute_values: [] attribute_values: []
) )
end end
@@ -7,9 +7,9 @@ class Api::V1::Accounts::NotificationsController < Api::V1::Accounts::BaseContro
before_action :set_current_page, only: [:index] before_action :set_current_page, only: [:index]
def index def index
@unread_count = current_user.notifications.where(account_id: current_account.id, read_at: nil).count @unread_count = notification_finder.unread_count
@count = notifications.count @notifications = notification_finder.perform
@notifications = notifications.page(@current_page).per(RESULTS_PER_PAGE) @count = notification_finder.count
end end
def read_all def read_all
@@ -35,7 +35,7 @@ class Api::V1::Accounts::NotificationsController < Api::V1::Accounts::BaseContro
end end
def unread_count def unread_count
@unread_count = current_user.notifications.where(account_id: current_account.id, read_at: nil).count @unread_count = notification_finder.unread_count
render json: @unread_count render json: @unread_count
end end
@@ -61,7 +61,7 @@ class Api::V1::Accounts::NotificationsController < Api::V1::Accounts::BaseContro
@current_page = params[:page] || 1 @current_page = params[:page] || 1
end end
def notifications def notification_finder
@notifications ||= current_user.notifications.where(account_id: current_account.id) @notification_finder ||= NotificationFinder.new(Current.user, Current.account, params)
end end
end end
@@ -14,7 +14,14 @@ module AccessTokenAuthHelper
render_unauthorized('Invalid Access Token') && return if @access_token.blank? render_unauthorized('Invalid Access Token') && return if @access_token.blank?
@resource = @access_token.owner @resource = @access_token.owner
Current.user = @resource if [User, AgentBot].include?(@resource.class) Current.user = @resource if allowed_current_user_type?(@resource)
end
def allowed_current_user_type?(resource)
return true if resource.is_a?(User)
return true if resource.is_a?(AgentBot)
false
end end
def validate_bot_access_token! def validate_bot_access_token!
@@ -1,6 +1,7 @@
class Public::Api::V1::Portals::BaseController < PublicController class Public::Api::V1::Portals::BaseController < PublicController
before_action :show_plain_layout before_action :show_plain_layout
before_action :set_color_scheme before_action :set_color_scheme
before_action :set_global_config
around_action :set_locale around_action :set_locale
after_action :allow_iframe_requests after_action :allow_iframe_requests
@@ -60,4 +61,8 @@ class Public::Api::V1::Portals::BaseController < PublicController
portal portal
render 'public/api/v1/portals/error/404', status: :not_found render 'public/api/v1/portals/error/404', status: :not_found
end end
def set_global_config
@global_config = GlobalConfig.get('LOGO_THUMBNAIL', 'BRAND_NAME', 'BRAND_URL')
end
end end
+47
View File
@@ -0,0 +1,47 @@
class NotificationFinder
attr_reader :current_user, :current_account, :params
RESULTS_PER_PAGE = 15
def initialize(current_user, current_account, params = {})
@current_user = current_user
@current_account = current_account
@params = params
set_up
end
def perform
notifications
end
def unread_count
@notifications.where(read_at: nil).count
end
def count
@notifications.count
end
private
def set_up
find_all_notifications
filter_by_status
end
def find_all_notifications
@notifications = current_user.notifications.where(account_id: @current_account.id)
end
def filter_by_status
@notifications = @notifications.where('snoozed_until > ?', DateTime.now.utc) if params[:status] == 'snoozed'
end
def current_page
params[:page] || 1
end
def notifications
@notifications.page(current_page).per(RESULTS_PER_PAGE).order(last_activity_at: :desc)
end
end
+1 -1
View File
@@ -53,7 +53,7 @@ module Api::V1::InboxesHelper
rescue StandardError => e rescue StandardError => e
raise StandardError, e.message raise StandardError, e.message
ensure ensure
ChatwootExceptionTracker.new(e).capture_exception if e.present? Rails.logger.error "[Api::V1::InboxesHelper] check_imap_connection failed with #{e.message}" if e.present?
end end
def check_smtp_connection(channel_data, smtp) def check_smtp_connection(channel_data, smtp)
@@ -37,7 +37,7 @@ module Api::V2::Accounts::ReportsHelper
business_hours: ActiveModel::Type::Boolean.new.cast(params[:business_hours]) business_hours: ActiveModel::Type::Boolean.new.cast(params[:business_hours])
} }
) )
).summary ).short_summary
end end
private private
@@ -1,4 +1,4 @@
@import '~vue2-datepicker/scss/index'; @import 'vue2-datepicker/scss/index';
.date-picker { .date-picker {
&.no-margin { &.no-margin {
@@ -1,4 +1,4 @@
@import '~dashboard/assets/scss/variables'; @import 'dashboard/assets/scss/variables';
.formulate-input { .formulate-input {
.formulate-input-errors { .formulate-input-errors {
@@ -1,623 +0,0 @@
// Foundation for Sites Settings
// -----------------------------
//
// Table of Contents:
//
// 1. Global
// 2. Breakpoints
// 3. The Grid
// 4. Base Typography
// 5. Typography Helpers
// 6. Abide
// 7. Accordion
// 8. Accordion Menu
// 9. Badge
// 10. Breadcrumbs
// 11. Button
// 12. Button Group
// 13. Callout
// 14. Card
// 15. Close Button
// 16. Drilldown
// 17. Dropdown
// 18. Dropdown Menu
// 19. Forms
// 20. Label
// 21. Media Object
// 22. Menu
// 23. Meter
// 24. Off-canvas
// 25. Orbit
// 26. Pagination
// 27. Progress Bar
// 28. Responsive Embed
// 29. Reveal
// 30. Slider
// 31. Switch
// 32. Table
// 33. Tabs
// 34. Thumbnail
// 35. Title Bar
// 36. Tooltip
// 37. Top Bar
@import '~foundation-sites/scss/util/util';
// 1. Global
// ---------
// Disable contrast warnings in Foundation.
$contrast-warnings: false;
$global-font-size: 16px;
$global-width: 100%;
$global-lineheight: 1.5;
$foundation-palette: (primary: $color-woot,
secondary: #5d7592,
success: #44ce4b,
warning: #ffc532,
alert: #ff382d);
$light-gray: #c0ccda;
$medium-gray: #8492a6;
$dark-gray: $color-gray;
$black: #000;
$white: #fff;
$body-background: $white;
$body-font-color: $color-body;
$body-font-family: 'PlusJakarta',
-apple-system,
system-ui,
BlinkMacSystemFont,
"Segoe UI",
Roboto,
"Helvetica Neue",
Tahoma,
Arial,
sans-serif;
$body-antialiased: true;
$global-margin: $space-small;
$global-padding: $space-small;
$global-weight-normal: normal;
$global-weight-bold: bold;
$global-radius: 0;
$global-text-direction: ltr;
$global-flexbox: false;
$print-transparent-backgrounds: true;
@include add-foundation-colors;
// 2. Breakpoints
// --------------
$breakpoints: (small: 0,
medium: 640px,
large: 1024px,
xlarge: 1200px,
xxlarge: 1400px,
xxxlarge: 1600px,
);
$print-breakpoint: large;
$breakpoint-classes: (small medium large);
// 3. The Grid
// -----------
$grid-row-width: $global-width;
$grid-column-count: 12;
$grid-column-gutter: (small: $zero,
medium: $zero);
$grid-column-align-edge: true;
$block-grid-max: 8;
// 4. Base Typography
// ------------------
$header-font-family: $body-font-family;
$header-font-weight: $font-weight-medium;
$header-font-style: normal;
$font-family-monospace: $body-font-family;
$header-color: $color-heading;
$header-lineheight: 1.4;
$header-margin-bottom: 0.3125rem;
$header-styles: (small: ("h1": ("font-size": 24),
"h2": ("font-size": 20),
"h3": ("font-size": 19),
"h4": ("font-size": 18),
"h5": ("font-size": 17),
"h6": ("font-size": 16)),
medium: ("h1": ("font-size": 48),
"h2": ("font-size": 40),
"h3": ("font-size": 31),
"h4": ("font-size": 25),
"h5": ("font-size": 20),
"h6": ("font-size": 16)));
$header-text-rendering: optimizeLegibility;
$small-font-size: 80%;
$header-small-font-color: $medium-gray;
$paragraph-lineheight: 1.65;
$paragraph-margin-bottom: var(--space-small);
$paragraph-text-rendering: optimizeLegibility;
$code-color: $black;
$code-font-family: $font-family-monospace;
$code-font-weight: $global-weight-normal;
$code-background: $light-gray;
$code-border: 1px solid $medium-gray;
$code-padding: rem-calc(2 5 1);
$anchor-color: $primary-color;
$anchor-color-hover: scale-color($anchor-color, $lightness: -14%);
$anchor-text-decoration: none;
$anchor-text-decoration-hover: none;
$hr-width: $global-width;
$hr-border: 1px solid $medium-gray;
$hr-margin: rem-calc(20) auto;
$list-lineheight: $paragraph-lineheight;
$list-margin-bottom: $paragraph-margin-bottom;
$list-style-type: disc;
$list-style-position: outside;
$list-side-margin: 0.78125rem;
$list-nested-side-margin: 0.78125rem;
$defnlist-margin-bottom: 0.6875rem;
$defnlist-term-weight: $global-weight-bold;
$defnlist-term-margin-bottom: 0.1875rem;
$blockquote-color: $dark-gray;
$blockquote-padding: rem-calc(9 20 0 19);
$blockquote-border: 1px solid $medium-gray;
$cite-font-size: rem-calc(13);
$cite-color: $dark-gray;
$cite-pseudo-content: '\2014 \0020';
$keystroke-font: $font-family-monospace;
$keystroke-color: $black;
$keystroke-background: $light-gray;
$keystroke-padding: rem-calc(2 4 0);
$keystroke-radius: $global-radius;
$abbr-underline: 1px dotted $black;
// 5. Typography Helpers
// ---------------------
$lead-font-size: $global-font-size * 1.25;
$lead-lineheight: 1.6;
$subheader-lineheight: 1.4;
$subheader-color: $dark-gray;
$subheader-font-weight: $global-weight-normal;
$subheader-margin-top: 0.125rem;
$subheader-margin-bottom: 0.3125rem;
$stat-font-size: 1.5625rem;
// 6. Abide
// --------
$abide-inputs: true;
$abide-labels: true;
$input-background-invalid: get-color(alert);
$form-label-color-invalid: get-color(alert);
$input-error-color: get-color(alert);
$input-error-font-size: rem-calc(12);
$input-error-font-weight: $global-weight-bold;
// 7. Accordion
// ------------
$accordion-background: $white;
$accordion-plusminus: true;
$accordion-title-font-size: rem-calc(12);
$accordion-item-color: $primary-color;
$accordion-item-background-hover: $light-gray;
$accordion-item-padding: 0.78125rem 0.625rem;
$accordion-content-background: $white;
$accordion-content-border: 1px solid $light-gray;
$accordion-content-color: $body-font-color;
$accordion-content-padding: 0.625rem;
// 8. Accordion Menu
// -----------------
$accordionmenu-arrows: true;
$accordionmenu-arrow-color: $primary-color;
$accordionmenu-arrow-size: 6px;
// 9. Badge
// --------
$badge-background: $primary-color;
$badge-color: $white;
$badge-color-alt: $black;
$badge-palette: $foundation-palette;
$badge-padding: var(--space-smaller);
$badge-minwidth: 2.1em;
$badge-font-size: var(--font-size-nano);
// 10. Breadcrumbs
// ---------------
$breadcrumbs-margin: 0 0 $global-margin 0;
$breadcrumbs-item-font-size: rem-calc(11);
$breadcrumbs-item-color: $primary-color;
$breadcrumbs-item-color-current: $black;
$breadcrumbs-item-color-disabled: $medium-gray;
$breadcrumbs-item-margin: 0.46875rem;
$breadcrumbs-item-uppercase: true;
$breadcrumbs-item-slash: true;
// 11. Button
// ----------
$button-padding: var(--space-smaller) 1em;
$button-margin: 0 0 $global-margin 0;
$button-fill: solid;
$button-background: $primary-color;
$button-background-hover: scale-color($button-background, $lightness: -15%);
$button-color: $white;
$button-color-alt: $white;
$button-radius: var(--border-radius-normal);
$button-sizes: (tiny: var(--font-size-micro),
small: var(--font-size-mini),
default: var(--font-size-small),
large: var(--font-size-medium));
$button-palette: $foundation-palette;
$button-opacity-disabled: 0.4;
$button-background-hover-lightness: -20%;
$button-hollow-hover-lightness: -50%;
$button-transition: background-color 0.25s ease-out,
color 0.25s ease-out;
// 12. Button Group
// ----------------
$buttongroup-margin: 0;
$buttongroup-spacing: 0;
$buttongroup-child-selector: '.button';
$buttongroup-expand-max: 6;
$buttongroup-radius-on-each: false;
// 13. Callout
// -----------
$callout-background: $white;
$callout-background-fade: 85%;
$callout-border: 1px solid rgba($black, 0.25);
$callout-margin: 0 0 0.625rem 0;
$callout-padding: 0.625rem;
$callout-font-color: $body-font-color;
$callout-font-color-alt: $body-background;
$callout-radius: $global-radius;
$callout-link-tint: 30%;
// 14. Card
// --------
$card-background: $white;
$card-font-color: $body-font-color;
$card-divider-background: $light-gray;
$card-border: 1px solid var(--color-border);
$card-shadow: var(--shadow-small);
$card-border-radius: var(--border-radius-normal);
$card-padding: var(--space-small);
$card-margin: $global-margin;
// 15. Close Button
// ----------------
$closebutton-position: right top;
$closebutton-offset-horizontal: (small: 0.66rem,
medium: 1rem);
$closebutton-offset-vertical: (small: 0.33em,
medium: 0.5rem);
$closebutton-size: (small: 1.5em,
medium: 2em);
$closebutton-lineheight: 1;
$closebutton-color: $dark-gray;
$closebutton-color-hover: $black;
// 16. Drilldown
// -------------
$drilldown-transition: transform 0.15s linear;
$drilldown-arrows: true;
$drilldown-arrow-color: $primary-color;
$drilldown-arrow-size: 6px;
$drilldown-background: $white;
// 17. Dropdown
// ------------
$dropdown-padding: 0.625rem;
$dropdown-background: $body-background;
$dropdown-border: 1px solid $medium-gray;
$dropdown-font-size: 0.625rem;
$dropdown-width: 300px;
$dropdown-radius: $global-radius;
$dropdown-sizes: (tiny: 100px,
small: 200px,
large: 400px);
// 18. Dropdown Menu
// -----------------
$dropdownmenu-arrows: true;
$dropdownmenu-arrow-color: $anchor-color;
$dropdownmenu-arrow-size: 6px;
$dropdownmenu-min-width: 200px;
$dropdownmenu-background: $white;
$dropdownmenu-border: 1px solid $medium-gray;
// 19. Forms
// ---------
$fieldset-border: 1px solid $light-gray;
$fieldset-padding: $space-two;
$fieldset-margin: $space-one $zero;
$legend-padding: rem-calc(0 3);
$form-spacing: $space-normal;
$helptext-color: $color-body;
$helptext-font-size: $font-size-small;
$helptext-font-style: italic;
$input-prefix-color: $color-body;
$input-prefix-background: var(--b-100);
$input-prefix-border: 1px solid $color-border;
$input-prefix-padding: 0.625rem;
$form-label-color: $color-body;
$form-label-font-size: rem-calc(14);
$form-label-font-weight: $font-weight-medium;
$form-label-line-height: 1.8;
$select-background: $white;
$select-triangle-color: $dark-gray;
$select-radius: var(--border-radius-normal);
$input-color: $color-body;
$input-placeholder-color: $light-gray;
$input-font-family: inherit;
$input-font-size: $font-size-default;
$input-font-weight: $global-weight-normal;
$input-background: $white;
$input-background-focus: $white;
$input-background-disabled: $light-gray;
$input-border: 1px solid var(--s-200);
$input-border-focus: 1px solid lighten($primary-color, 15%);
$input-shadow: 0;
$input-shadow-focus: 0;
$input-cursor-disabled: not-allowed;
$input-transition: border-color 0.25s ease-in-out;
$input-number-spinners: true;
$input-radius: var(--border-radius-normal);
$form-button-radius: var(--border-radius-normal);
// 20. Label
// ---------
$label-background: $white;
$label-color: $black;
$label-color-alt: $black;
$label-palette: $foundation-palette;
$label-font-size: $font-size-mini;
$label-padding: $space-smaller $space-small;
$label-radius: var(--border-radius-small);
// 21. Media Object
// ----------------
$mediaobject-margin-bottom: $global-margin;
$mediaobject-section-padding: $global-padding;
$mediaobject-image-width-stacked: 100%;
// 22. Menu
// --------
$menu-margin: 0;
$menu-margin-nested: $space-medium;
$menu-item-padding: $space-slab;
$menu-item-color-active: $white;
$menu-item-background-active: $color-background;
$menu-icon-spacing: 0.15625rem;
$menu-item-background-hover: $light-gray;
$menu-border: $light-gray;
// 23. Meter
// ---------
$meter-height: 0.625rem;
$meter-radius: $global-radius;
$meter-background: $medium-gray;
$meter-fill-good: $success-color;
$meter-fill-medium: $warning-color;
$meter-fill-bad: $alert-color;
// 24. Off-canvas
// --------------
$offcanvas-sizes: (small: 14.375,
medium: 14.375,
);
$offcanvas-vertical-sizes: (small: 14.375,
medium: 14.375,
);
$offcanvas-background: $light-gray;
$offcanvas-shadow: 0 0 10px rgba($black, 0.7);
$offcanvas-push-zindex: 1;
$offcanvas-overlap-zindex: 10;
$offcanvas-reveal-zindex: 1;
$offcanvas-transition-length: 0.5s;
$offcanvas-transition-timing: ease;
$offcanvas-fixed-reveal: true;
$offcanvas-exit-background: rgba($white, 0.25);
$maincontent-class: 'off-canvas-content';
// 25. Orbit
// ---------
$orbit-bullet-background: $medium-gray;
$orbit-bullet-background-active: $dark-gray;
$orbit-bullet-diameter: 0.75rem;
$orbit-bullet-margin: 0.0625rem;
$orbit-bullet-margin-top: 0.5rem;
$orbit-bullet-margin-bottom: 0.5rem;
$orbit-caption-background: rgba($black, 0.5);
$orbit-caption-padding: 0.625rem;
$orbit-control-background-hover: rgba($black, 0.5);
$orbit-control-padding: 0.625rem;
$orbit-control-zindex: 10;
// 26. Pagination
// --------------
$pagination-font-size: rem-calc(14);
$pagination-margin-bottom: $global-margin;
$pagination-item-color: $black;
$pagination-item-padding: rem-calc(3 10);
$pagination-item-spacing: rem-calc(1);
$pagination-radius: $global-radius;
$pagination-item-background-hover: $light-gray;
$pagination-item-background-current: $primary-color;
$pagination-item-color-current: $white;
$pagination-item-color-disabled: $medium-gray;
$pagination-ellipsis-color: $black;
$pagination-mobile-items: false;
$pagination-mobile-current-item: false;
$pagination-arrows: true;
// 27. Progress Bar
// ----------------
$progress-height: 0.625rem;
$progress-background: $medium-gray;
$progress-margin-bottom: $global-margin;
$progress-meter-background: $primary-color;
$progress-radius: $global-radius;
// 28. Responsive Embed
// --------------------
$responsive-embed-margin-bottom: rem-calc(16);
$responsive-embed-ratios: (default: 4 by 3,
widescreen: 16 by 9);
// 29. Reveal
// ----------
$reveal-background: $white;
$reveal-width: 600px;
$reveal-max-width: $global-width;
$reveal-padding: $global-padding;
$reveal-border: 1px solid $medium-gray;
$reveal-radius: $global-radius;
$reveal-zindex: 1005;
$reveal-overlay-background: rgba($black, 0.45);
// 30. Slider
// ----------
$slider-width-vertical: 0.3125rem;
$slider-transition: all 0.2s ease-in-out;
$slider-height: 0.3125rem;
$slider-background: $light-gray;
$slider-fill-background: $medium-gray;
$slider-handle-height: 0.875rem;
$slider-handle-width: 0.875rem;
$slider-handle-background: $primary-color;
$slider-opacity-disabled: 0.25;
$slider-radius: $global-radius;
// 31. Switch
// ----------
$switch-background: $light-gray;
$switch-background-active: $primary-color;
$switch-height: $space-two;
$switch-height-tiny: $space-slab;
$switch-height-small: $space-normal;
$switch-height-large: $space-large;
$switch-radius: $space-large;
$switch-margin: $global-margin;
$switch-paddle-background: $white;
$switch-paddle-offset: $space-micro;
$switch-paddle-radius: $space-large;
$switch-paddle-transition: all 0.15s ease-out;
// 32. Table
// ---------
$table-background: transparent;
$table-color-scale: 5%;
$table-border: 1px solid transparent;
$table-padding: rem-calc(8 10 10);
$table-hover-scale: 2%;
$table-row-hover: darken($table-background, $table-hover-scale);
$table-row-stripe-hover: darken($table-background,
$table-color-scale + $table-hover-scale);
$table-is-striped: false;
$table-striped-background: smart-scale($table-background, $table-color-scale);
$table-stripe: even;
$table-head-background: smart-scale($table-background, $table-color-scale / 2);
$table-head-row-hover: darken($table-head-background, $table-hover-scale);
$table-foot-background: smart-scale($table-background, $table-color-scale);
$table-foot-row-hover: darken($table-foot-background, $table-hover-scale);
$table-head-font-color: $body-font-color;
$table-foot-font-color: $body-font-color;
$show-header-for-stacked: false;
// 33. Tabs
// --------
$tab-margin: 0;
$tab-background: transparent;
$tab-background-active: transparent;
$tab-item-font-size: $font-size-small;
$tab-item-background-hover: transparent;
$tab-item-padding: $space-one $zero;
$tab-color: $primary-color;
$tab-active-color: $primary-color;
$tab-expand-max: 6;
$tab-content-background: transparent;
$tab-content-border: transparent;
$tab-content-color: foreground($tab-background, $primary-color);
$tab-content-padding: 0.625rem;
// 34. Thumbnail
// -------------
$thumbnail-border: solid 4px $white;
$thumbnail-margin-bottom: $global-margin;
$thumbnail-shadow: 0 0 0 1px rgba($black, 0.2);
$thumbnail-shadow-hover: 0 0 6px 1px rgba($primary-color, 0.5);
$thumbnail-transition: box-shadow 200ms ease-out;
$thumbnail-radius: $global-radius;
// 35. Title Bar
// -------------
$titlebar-background: $black;
$titlebar-color: $white;
$titlebar-padding: 0.3125rem;
$titlebar-text-font-weight: bold;
$titlebar-icon-color: $white;
$titlebar-icon-color-hover: $medium-gray;
$titlebar-icon-spacing: 0.15625rem;
// 36. Tooltip
// -----------
$has-tip-font-weight: $global-weight-bold;
$has-tip-border-bottom: dotted 1px $dark-gray;
$tooltip-background-color: $black;
$tooltip-color: $white;
$tooltip-padding: 0.46875rem;
$tooltip-font-size: $font-size-mini;
$tooltip-pip-width: 0.46875rem;
$tooltip-pip-height: $tooltip-pip-width * 0.866;
$tooltip-radius: $global-radius;
// 37. Top Bar
// -----------
$topbar-padding: 0.3125;
$topbar-background: $light-gray;
$topbar-submenu-background: $topbar-background;
$topbar-title-spacing: 0.3125 0.625rem 0.3125 0;
$topbar-input-width: 200px;
$topbar-unstack-breakpoint: medium;
// Internal variable that contains the flex justifying options
$-zf-flex-justify: -zf-flex-justify($global-text-direction);
$menu-items-padding: $space-one;
$xy-grid: false;
@@ -2,11 +2,6 @@
@apply bg-slate-25 dark:bg-slate-800; @apply bg-slate-25 dark:bg-slate-800;
} }
.flex-center {
@include flex-align(center, middle);
display: flex;
}
.bottom-space-fix { .bottom-space-fix {
margin-bottom: auto; margin-bottom: auto;
} }
@@ -1,5 +1,5 @@
@import '~dashboard/assets/scss/variables'; @import 'dashboard/assets/scss/variables';
@import '~widget/assets/scss/mixins'; @import 'widget/assets/scss/mixins';
$spinner-before-border-color: rgba(255, 255, 255, 0.7); $spinner-before-border-color: rgba(255, 255, 255, 0.7);
@@ -89,9 +89,6 @@ $swift-ease-out-duration: .4s !default;
$swift-ease-out-function: cubic-bezier(0.37, 0, 0.63, 1) !default; $swift-ease-out-function: cubic-bezier(0.37, 0, 0.63, 1) !default;
$swift-ease-out: all $swift-ease-out-duration $swift-ease-out-function !default; $swift-ease-out: all $swift-ease-out-duration $swift-ease-out-function !default;
// Ionicons
$ionicons-font-path: '~ionicons/fonts';
// Transitions // Transitions
$transition-ease-in: all 0.250s ease-in; $transition-ease-in: all 0.250s ease-in;
@@ -15,36 +15,13 @@
@import 'variables'; @import 'variables';
@import 'mixins'; @import 'mixins';
@import 'foundation-settings';
@import 'helper-classes'; @import 'helper-classes';
@import 'formulate'; @import 'formulate';
@import 'date-picker'; @import 'date-picker';
@import 'foundation-sites/scss/foundation';
@include foundation-everything($flex: true);
@include foundation-prototype-text-utilities;
@include foundation-prototype-text-transformation;
@include foundation-prototype-text-decoration;
@include foundation-prototype-font-styling;
@include foundation-prototype-list-style-type;
@include foundation-prototype-rounded;
@include foundation-prototype-bordered;
@include foundation-prototype-shadow;
@include foundation-prototype-separator;
@include foundation-prototype-overflow;
@include foundation-prototype-display;
@include foundation-prototype-position;
@include foundation-prototype-border-box;
@include foundation-prototype-border-none;
@include foundation-prototype-sizing;
@include foundation-prototype-spacing;
@import 'typography'; @import 'typography';
@import 'layout'; @import 'layout';
@import 'animations'; @import 'animations';
@import 'foundation-custom';
@import 'rtl'; @import 'rtl';
@import 'widgets/buttons'; @import 'widgets/buttons';
@@ -52,15 +29,11 @@
@import 'widgets/conversation-card'; @import 'widgets/conversation-card';
@import 'widgets/conversation-view'; @import 'widgets/conversation-view';
@import 'widgets/forms'; @import 'widgets/forms';
@import 'widgets/login';
@import 'widgets/modal'; @import 'widgets/modal';
@import 'widgets/reply-box'; @import 'widgets/reply-box';
@import 'widgets/report'; @import 'widgets/report';
@import 'widgets/search-box';
@import 'widgets/sidemenu';
@import 'widgets/snackbar'; @import 'widgets/snackbar';
@import 'widgets/states'; @import 'widgets/states';
@import 'widgets/status-bar';
@import 'widgets/tabs'; @import 'widgets/tabs';
@import 'widgets/woot-tables'; @import 'widgets/woot-tables';
@@ -69,7 +42,6 @@
@import 'plugins/multiselect'; @import 'plugins/multiselect';
@import 'plugins/dropdown'; @import 'plugins/dropdown';
@import '~shared/assets/stylesheets/ionicons';
@import 'utility-helpers'; @import 'utility-helpers';
.tooltip { .tooltip {
@@ -10,21 +10,14 @@
@import 'variables'; @import 'variables';
@import 'vue-multiselect/dist/vue-multiselect.min.css'; @import 'vue-multiselect/dist/vue-multiselect.min.css';
@import '~shared/assets/stylesheets/ionicons';
@import 'mixins'; @import 'mixins';
@import 'foundation-settings';
@import 'helper-classes'; @import 'helper-classes';
@import 'foundation-sites/scss/foundation';
@include foundation-prototype-spacing;
@include foundation-everything($flex: true);
@import 'typography'; @import 'typography';
@import 'layout'; @import 'layout';
@import 'animations'; @import 'animations';
@import 'foundation-custom';
@import 'widgets/buttons'; @import 'widgets/buttons';
@import 'widgets/forms'; @import 'widgets/forms';
@@ -1,66 +0,0 @@
.auth-wrap {
width: 100%;
}
// Outside login wrapper
.login {
@include full-height;
overflow-y: auto;
padding-top: $space-larger * 1.2;
.login__hero {
margin-bottom: $space-larger;
.hero__logo {
width: 180px;
}
.hero__title {
font-weight: $font-weight-light;
margin-top: $space-larger;
}
.hero__sub {
color: $medium-gray;
font-size: $font-size-medium;
}
}
// Login box
.login-box {
@include background-white;
@include border-normal;
@include elegant-card;
border-radius: $space-smaller;
padding: $space-large;
label {
color: $color-gray;
font-size: $font-size-default;
input {
font-size: $font-size-default;
height: $space-larger;
padding: $space-slab;
}
.error {
font-size: $font-size-small;
}
}
.button {
height: $space-larger;
}
}
.sigin__footer {
font-size: $font-size-default;
padding: $space-medium;
> a {
font-weight: $font-weight-bold;
}
}
}
@@ -1,7 +1,5 @@
.modal-mask { .modal-mask {
// @include flex; @apply flex items-center justify-center bg-modal-backdrop-light dark:bg-modal-backdrop-dark z-[9990] h-full left-0 fixed top-0 w-full;
// @include flex-align(center, middle);
@apply flex items-center justify-center bg-modal dark:bg-modal z-[9990] h-full left-0 fixed top-0 w-full;
} }
.page-top-bar { .page-top-bar {
@@ -45,8 +43,6 @@
} }
.modal-footer { .modal-footer {
// @include flex;
// @include flex-align($x: flex-end, $y: middle);
@apply flex justify-end items-center py-2 px-0 gap-2; @apply flex justify-end items-center py-2 px-0 gap-2;
&.justify-content-end { &.justify-content-end {
@@ -8,7 +8,7 @@
.reply-box__top { .reply-box__top {
.icon { .icon {
color: $medium-gray; color: var(--slate-500);
cursor: pointer; cursor: pointer;
font-size: $font-size-medium; font-size: $font-size-medium;
margin-right: $space-small; margin-right: $space-small;
@@ -34,7 +34,7 @@
resize: none; resize: none;
} }
> textarea { >textarea {
@include ghost-input(); @include ghost-input();
background: transparent; background: transparent;
margin: 0; margin: 0;
@@ -52,7 +52,7 @@
.reply-box__top { .reply-box__top {
@apply bg-yellow-100 dark:bg-yellow-800; @apply bg-yellow-100 dark:bg-yellow-800;
> input { >input {
@apply bg-yellow-100 dark:bg-yellow-800; @apply bg-yellow-100 dark:bg-yellow-800;
} }
} }
@@ -1,45 +1,10 @@
.side-menu {
i {
margin-right: var(--space-smaller);
min-width: var(--space-two);
}
}
.sidebar {
z-index: 1024 - 1;
//logo
.logo {
img {
max-height: 108px;
padding: $woot-logo-padding;
}
}
.nested {
a {
font-size: var(--font-size-small);
margin-bottom: var(--space-micro);
margin-top: var(--space-micro);
.inbox-icon {
display: inline-block;
margin-right: var(--space-micro);
min-width: var(--space-normal);
text-align: center;
}
}
}
}
// bottom-nav // bottom-nav
.bottom-nav { .bottom-nav {
@include flex; @include flex;
@include space-between-column; @include space-between-column;
@include border-normal-top; @include border-normal-top;
flex-direction: column; flex-direction: column;
padding: var(--space-one) var(--space-normal) var(--space-one) padding: var(--space-one) var(--space-normal) var(--space-one) var(--space-one);
var(--space-one);
position: relative; position: relative;
&:hover { &:hover {
@@ -519,6 +519,9 @@ export default {
}, },
}, },
watch: { watch: {
teamId() {
this.updateVirtualListProps('teamId', this.teamId);
},
activeTeam() { activeTeam() {
this.resetAndFetchData(); this.resetAndFetchData();
}, },
@@ -13,7 +13,7 @@
<div class="flex items-center justify-between w-full"> <div class="flex items-center justify-between w-full">
<span <span
class="attribute-name" class="attribute-name"
:class="{ error: $v.editedValue.$error }" :class="{ error: v$.editedValue.$error }"
> >
{{ label }} {{ label }}
</span> </span>
@@ -39,8 +39,8 @@
:type="inputType" :type="inputType"
class="input-group-field" class="input-group-field"
autofocus="true" autofocus="true"
:class="{ error: $v.editedValue.$error }" :class="{ error: v$.editedValue.$error }"
@blur="$v.editedValue.$touch" @blur="v$.editedValue.$touch"
@keyup.enter="onUpdate" @keyup.enter="onUpdate"
/> />
<div class="input-group-button"> <div class="input-group-button">
@@ -122,25 +122,37 @@
<script> <script>
import { format, parseISO } from 'date-fns'; import { format, parseISO } from 'date-fns';
import { required, url } from 'vuelidate/lib/validators'; import { required, url } from '@vuelidate/validators';
import { BUS_EVENTS } from 'shared/constants/busEvents'; import { BUS_EVENTS } from 'shared/constants/busEvents';
import MultiselectDropdown from 'shared/components/ui/MultiselectDropdown.vue'; import MultiselectDropdown from 'shared/components/ui/MultiselectDropdown.vue';
import { isValidURL } from '../helper/URLHelper'; import { isValidURL } from '../helper/URLHelper';
import customAttributeMixin from '../mixins/customAttributeMixin';
const DATE_FORMAT = 'yyyy-MM-dd'; const DATE_FORMAT = 'yyyy-MM-dd';
import { useVuelidate } from '@vuelidate/core';
export default { export default {
components: { components: {
MultiselectDropdown, MultiselectDropdown,
}, },
mixins: [customAttributeMixin],
props: { props: {
label: { type: String, required: true }, label: { type: String, required: true },
values: { type: Array, default: () => [] }, values: { type: Array, default: () => [] },
value: { type: [String, Number, Boolean], default: '' }, value: { type: [String, Number, Boolean], default: '' },
showActions: { type: Boolean, default: false }, showActions: { type: Boolean, default: false },
attributeType: { type: String, default: 'text' }, attributeType: { type: String, default: 'text' },
attributeRegex: {
type: String,
default: null,
},
regexCue: { type: String, default: null },
regexEnabled: { type: Boolean, default: false },
attributeKey: { type: String, required: true }, attributeKey: { type: String, required: true },
contactId: { type: Number, default: null }, contactId: { type: Number, default: null },
}, },
setup() {
return { v$: useVuelidate() };
},
data() { data() {
return { return {
isEditing: false, isEditing: false,
@@ -198,12 +210,17 @@ export default {
return this.isAttributeTypeLink ? 'url' : this.attributeType; return this.isAttributeTypeLink ? 'url' : this.attributeType;
}, },
shouldShowErrorMessage() { shouldShowErrorMessage() {
return this.$v.editedValue.$error; return this.v$.editedValue.$error;
}, },
errorMessage() { errorMessage() {
if (this.$v.editedValue.url) { if (this.v$.editedValue.url) {
return this.$t('CUSTOM_ATTRIBUTES.VALIDATIONS.INVALID_URL'); return this.$t('CUSTOM_ATTRIBUTES.VALIDATIONS.INVALID_URL');
} }
if (!this.v$.editedValue.regexValidation) {
return this.regexCue
? this.regexCue
: this.$t('CUSTOM_ATTRIBUTES.VALIDATIONS.INVALID_INPUT');
}
return this.$t('CUSTOM_ATTRIBUTES.VALIDATIONS.REQUIRED'); return this.$t('CUSTOM_ATTRIBUTES.VALIDATIONS.REQUIRED');
}, },
}, },
@@ -221,7 +238,15 @@ export default {
}; };
} }
return { return {
editedValue: { required }, editedValue: {
required,
regexValidation: value => {
return !(
this.attributeRegex &&
!this.getRegexp(this.attributeRegex).test(value)
);
},
},
}; };
}, },
mounted() { mounted() {
@@ -259,8 +284,8 @@ export default {
this.attributeType === 'date' this.attributeType === 'date'
? parseISO(this.editedValue) ? parseISO(this.editedValue)
: this.editedValue; : this.editedValue;
this.$v.$touch(); this.v$.$touch();
if (this.$v.$invalid) { if (this.v$.$invalid) {
return; return;
} }
this.isEditing = false; this.isEditing = false;
@@ -281,11 +306,14 @@ export default {
.checkbox-wrap { .checkbox-wrap {
@apply flex items-center; @apply flex items-center;
} }
.checkbox { .checkbox {
@apply my-0 mr-2 ml-0; @apply my-0 mr-2 ml-0;
} }
.attribute-name { .attribute-name {
@apply w-full text-slate-800 dark:text-slate-100; @apply w-full text-slate-800 dark:text-slate-100;
&.error { &.error {
@apply text-red-400 dark:text-red-500; @apply text-red-400 dark:text-red-500;
} }
@@ -302,6 +330,7 @@ export default {
.value { .value {
@apply bg-slate-50 dark:bg-slate-700 mb-0; @apply bg-slate-50 dark:bg-slate-700 mb-0;
} }
.edit-button { .edit-button {
@apply block; @apply block;
} }
@@ -311,10 +340,12 @@ export default {
::v-deep { ::v-deep {
.selector-wrap { .selector-wrap {
@apply m-0 top-1; @apply m-0 top-1;
.selector-name { .selector-name {
@apply ml-0; @apply ml-0;
} }
} }
.name { .name {
@apply ml-0; @apply ml-0;
} }
+15 -15
View File
@@ -1,29 +1,29 @@
/* eslint no-plusplus: 0 */ /* eslint no-plusplus: 0 */
import AvatarUploader from './widgets/forms/AvatarUploader.vue'; import AvatarUploader from './widgets/forms/AvatarUploader.vue';
import Bar from './widgets/chart/BarChart'; import Bar from './widgets/chart/BarChart';
import Button from './ui/WootButton'; import Button from './ui/WootButton.vue';
import Code from './Code'; import Code from './Code.vue';
import ColorPicker from './widgets/ColorPicker'; import ColorPicker from './widgets/ColorPicker.vue';
import ConfirmDeleteModal from './widgets/modal/ConfirmDeleteModal.vue'; import ConfirmDeleteModal from './widgets/modal/ConfirmDeleteModal.vue';
import ConfirmModal from './widgets/modal/ConfirmationModal.vue'; import ConfirmModal from './widgets/modal/ConfirmationModal.vue';
import ContextMenu from './ui/ContextMenu.vue'; import ContextMenu from './ui/ContextMenu.vue';
import DeleteModal from './widgets/modal/DeleteModal.vue'; import DeleteModal from './widgets/modal/DeleteModal.vue';
import DropdownItem from 'shared/components/ui/dropdown/DropdownItem'; import DropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue';
import DropdownMenu from 'shared/components/ui/dropdown/DropdownMenu'; import DropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue';
import FeatureToggle from './widgets/FeatureToggle'; import FeatureToggle from './widgets/FeatureToggle.vue';
import HorizontalBar from './widgets/chart/HorizontalBarChart'; import HorizontalBar from './widgets/chart/HorizontalBarChart';
import Input from './widgets/forms/Input.vue'; import Input from './widgets/forms/Input.vue';
import PhoneInput from './widgets/forms/PhoneInput.vue'; import PhoneInput from './widgets/forms/PhoneInput.vue';
import Label from './ui/Label'; import Label from './ui/Label.vue';
import LoadingState from './widgets/LoadingState'; import LoadingState from './widgets/LoadingState.vue';
import Modal from './Modal'; import Modal from './Modal.vue';
import ModalHeader from './ModalHeader'; import ModalHeader from './ModalHeader.vue';
import ReportStatsCard from './widgets/ReportStatsCard'; import ReportStatsCard from './widgets/ReportStatsCard.vue';
import SidemenuIcon from './SidemenuIcon'; import SidemenuIcon from './SidemenuIcon.vue';
import Spinner from 'shared/components/Spinner'; import Spinner from 'shared/components/Spinner.vue';
import SubmitButton from './buttons/FormSubmitButton'; import SubmitButton from './buttons/FormSubmitButton.vue';
import Tabs from './ui/Tabs/Tabs'; import Tabs from './ui/Tabs/Tabs';
import TabsItem from './ui/Tabs/TabsItem'; import TabsItem from './ui/Tabs/TabsItem.vue';
import Thumbnail from './widgets/Thumbnail.vue'; import Thumbnail from './widgets/Thumbnail.vue';
const WootUIKit = { const WootUIKit = {
@@ -19,13 +19,13 @@
<form class="flex flex-col w-full" @submit.prevent="addAccount"> <form class="flex flex-col w-full" @submit.prevent="addAccount">
<div class="w-full"> <div class="w-full">
<label :class="{ error: $v.accountName.$error }"> <label :class="{ error: v$.accountName.$error }">
{{ $t('CREATE_ACCOUNT.FORM.NAME.LABEL') }} {{ $t('CREATE_ACCOUNT.FORM.NAME.LABEL') }}
<input <input
v-model.trim="accountName" v-model.trim="accountName"
type="text" type="text"
:placeholder="$t('CREATE_ACCOUNT.FORM.NAME.PLACEHOLDER')" :placeholder="$t('CREATE_ACCOUNT.FORM.NAME.PLACEHOLDER')"
@input="$v.accountName.$touch" @input="v$.accountName.$touch"
/> />
</label> </label>
</div> </div>
@@ -33,8 +33,8 @@
<div class="w-full"> <div class="w-full">
<woot-submit-button <woot-submit-button
:disabled=" :disabled="
$v.accountName.$invalid || v$.accountName.$invalid ||
$v.accountName.$invalid || v$.accountName.$invalid ||
uiFlags.isCreating uiFlags.isCreating
" "
:button-text="$t('CREATE_ACCOUNT.FORM.SUBMIT')" :button-text="$t('CREATE_ACCOUNT.FORM.SUBMIT')"
@@ -49,9 +49,10 @@
</template> </template>
<script> <script>
import { required, minLength } from 'vuelidate/lib/validators'; import { required, minLength } from '@vuelidate/validators';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import { useVuelidate } from '@vuelidate/core';
export default { export default {
mixins: [alertMixin], mixins: [alertMixin],
@@ -65,6 +66,9 @@ export default {
default: true, default: true,
}, },
}, },
setup() {
return { v$: useVuelidate() };
},
data() { data() {
return { return {
accountName: '', accountName: '',
@@ -56,7 +56,7 @@
class="bg-slate-50 dark:bg-slate-700 rounded text-xxs font-medium mx-1 py-0 px-1" class="bg-slate-50 dark:bg-slate-700 rounded text-xxs font-medium mx-1 py-0 px-1"
:class=" :class="
isCountZero isCountZero
? `text-slate-300 dark:text-slate-700` ? `text-slate-300 dark:text-slate-500`
: `text-slate-700 dark:text-slate-50` : `text-slate-700 dark:text-slate-50`
" "
> >
@@ -1,4 +1,6 @@
export default { import { defineComponent } from 'vue';
export default defineComponent({
name: 'WootTabs', name: 'WootTabs',
props: { props: {
index: { index: {
@@ -73,19 +75,25 @@ export default {
}); });
const leftButton = this.createScrollButton(createElement, 'left'); const leftButton = this.createScrollButton(createElement, 'left');
const rightButton = this.createScrollButton(createElement, 'right'); const rightButton = this.createScrollButton(createElement, 'right');
return ( return createElement(
<div 'div',
class={{ {
class: {
'tabs--container--with-border': this.border, 'tabs--container--with-border': this.border,
'tabs--container': true, 'tabs--container': true,
}} },
> },
{leftButton} [
<ul class={{ tabs: true, 'tabs--with-scroll': this.hasScroll }}> leftButton,
{Tabs} createElement(
</ul> 'ul',
{rightButton} {
</div> class: { tabs: true, 'tabs--with-scroll': this.hasScroll },
},
Tabs
),
rightButton,
]
); );
}, },
}; });
@@ -12,11 +12,11 @@
<woot-input <woot-input
v-model="value" v-model="value"
type="text" type="text"
:class="{ error: $v.value.$error }" :class="{ error: v$.value.$error }"
:placeholder=" :placeholder="
$t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.KEY_PLACEHOLDER') $t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.KEY_PLACEHOLDER')
" "
@blur="$v.value.$touch" @blur="v$.value.$touch"
/> />
</div> </div>
<div class="flex flex-row justify-between gap-2 py-2 px-0 w-full"> <div class="flex flex-row justify-between gap-2 py-2 px-0 w-full">
@@ -27,7 +27,7 @@
<woot-button variant="clear" @click.prevent="onDismiss"> <woot-button variant="clear" @click.prevent="onDismiss">
{{ $t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.BUTTONS.DISMISS') }} {{ $t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.BUTTONS.DISMISS') }}
</woot-button> </woot-button>
<woot-button :is-disabled="$v.value.$invalid"> <woot-button :is-disabled="v$.value.$invalid">
{{ $t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.BUTTONS.FINISH') }} {{ $t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.BUTTONS.FINISH') }}
</woot-button> </woot-button>
</div> </div>
@@ -37,15 +37,19 @@
</template> </template>
<script> <script>
import { required } from 'vuelidate/lib/validators'; import { required } from '@vuelidate/validators';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import aiMixin from 'dashboard/mixins/aiMixin'; import aiMixin from 'dashboard/mixins/aiMixin';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import { OPEN_AI_EVENTS } from 'dashboard/helper/AnalyticsHelper/events'; import { OPEN_AI_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
import { useVuelidate } from '@vuelidate/core';
export default { export default {
mixins: [aiMixin, alertMixin, uiSettingsMixin], mixins: [aiMixin, alertMixin, uiSettingsMixin],
setup() {
return { v$: useVuelidate() };
},
data() { data() {
return { return {
value: '', value: '',
@@ -53,8 +53,8 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import '~dashboard/assets/scss/variables'; @import 'dashboard/assets/scss/variables';
@import '~dashboard/assets/scss/mixins'; @import 'dashboard/assets/scss/mixins';
.colorpicker { .colorpicker {
position: relative; position: relative;
@@ -705,10 +705,11 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
@import '~@chatwoot/prosemirror-schema/src/styles/base.scss'; @import '@chatwoot/prosemirror-schema/src/styles/base.scss';
.ProseMirror-menubar-wrapper { .ProseMirror-menubar-wrapper {
@apply flex flex-col; @apply flex flex-col;
.ProseMirror-menubar { .ProseMirror-menubar {
min-height: var(--space-two) !important; min-height: var(--space-two) !important;
@apply -ml-2.5 pb-0 bg-white dark:bg-slate-900 text-slate-700 dark:text-slate-100; @apply -ml-2.5 pb-0 bg-white dark:bg-slate-900 text-slate-700 dark:text-slate-100;
@@ -717,6 +718,7 @@ export default {
@apply bg-slate-75 dark:bg-slate-800; @apply bg-slate-75 dark:bg-slate-800;
} }
} }
> .ProseMirror { > .ProseMirror {
@apply p-0 break-words text-slate-800 dark:text-slate-100; @apply p-0 break-words text-slate-800 dark:text-slate-100;
@@ -101,10 +101,10 @@
<transition name="modal-fade"> <transition name="modal-fade">
<div <div
v-show="$refs.upload && $refs.upload.dropActive" v-show="$refs.upload && $refs.upload.dropActive"
class="fixed top-0 bottom-0 left-0 right-0 z-20 flex flex-col items-center justify-center w-full h-full gap-2 text-slate-600 dark:text-slate-200 bg-white_transparent dark:bg-black_transparent" class="fixed top-0 bottom-0 left-0 right-0 z-20 flex flex-col items-center justify-center w-full h-full gap-2 text-slate-900 dark:text-slate-50 bg-modal-backdrop-light dark:bg-modal-backdrop-dark"
> >
<fluent-icon icon="cloud-backup" size="40" /> <fluent-icon icon="cloud-backup" size="40" />
<h4 class="page-sub-title text-slate-600 dark:text-slate-200"> <h4 class="page-sub-title text-slate-900 dark:text-slate-50">
{{ $t('CONVERSATION.REPLYBOX.DRAG_DROP') }} {{ $t('CONVERSATION.REPLYBOX.DRAG_DROP') }}
</h4> </h4>
</div> </div>
@@ -41,7 +41,7 @@
:show-query-operator="i !== appliedFilters.length - 1" :show-query-operator="i !== appliedFilters.length - 1"
:show-user-input="showUserInput(appliedFilters[i].filter_operator)" :show-user-input="showUserInput(appliedFilters[i].filter_operator)"
:grouped-filters="true" :grouped-filters="true"
:v="$v.appliedFilters.$each[i]" :v="v$.appliedFilters.$each[i]"
@resetFilter="resetFilter(i, appliedFilters[i])" @resetFilter="resetFilter(i, appliedFilters[i])"
@removeFilter="removeFilter(i)" @removeFilter="removeFilter(i)"
/> />
@@ -80,7 +80,7 @@
<script> <script>
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import { required, requiredIf } from 'vuelidate/lib/validators'; import { required, requiredIf } from '@vuelidate/validators';
import FilterInputBox from '../FilterInput/Index.vue'; import FilterInputBox from '../FilterInput/Index.vue';
import languages from './advancedFilterItems/languages'; import languages from './advancedFilterItems/languages';
import countries from 'shared/constants/countries.js'; import countries from 'shared/constants/countries.js';
@@ -89,6 +89,7 @@ import { filterAttributeGroups } from './advancedFilterItems';
import filterMixin from 'shared/mixins/filterMixin'; import filterMixin from 'shared/mixins/filterMixin';
import * as OPERATORS from 'dashboard/components/widgets/FilterInput/FilterOperatorTypes.js'; import * as OPERATORS from 'dashboard/components/widgets/FilterInput/FilterOperatorTypes.js';
import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events'; import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events';
import { useVuelidate } from '@vuelidate/core';
export default { export default {
components: { components: {
@@ -117,6 +118,9 @@ export default {
default: false, default: false,
}, },
}, },
setup() {
return { v$: useVuelidate() };
},
validations: { validations: {
appliedFilters: { appliedFilters: {
required, required,
@@ -347,8 +351,8 @@ export default {
} }
}, },
submitFilterQuery() { submitFilterQuery() {
this.$v.$touch(); this.v$.$touch();
if (this.$v.$invalid) return; if (this.v$.$invalid) return;
this.$store.dispatch( this.$store.dispatch(
'setConversationFilters', 'setConversationFilters',
JSON.parse(JSON.stringify(this.appliedFilters)) JSON.parse(JSON.stringify(this.appliedFilters))
@@ -45,14 +45,14 @@
}}</label> }}</label>
</div> </div>
<div v-if="sentToOtherEmailAddress" class="w-[50%] mt-1"> <div v-if="sentToOtherEmailAddress" class="w-[50%] mt-1">
<label :class="{ error: $v.email.$error }"> <label :class="{ error: v$.email.$error }">
<input <input
v-model.trim="email" v-model.trim="email"
type="text" type="text"
:placeholder="$t('EMAIL_TRANSCRIPT.FORM.EMAIL.PLACEHOLDER')" :placeholder="$t('EMAIL_TRANSCRIPT.FORM.EMAIL.PLACEHOLDER')"
@input="$v.email.$touch" @input="v$.email.$touch"
/> />
<span v-if="$v.email.$error" class="message"> <span v-if="v$.email.$error" class="message">
{{ $t('EMAIL_TRANSCRIPT.FORM.EMAIL.ERROR') }} {{ $t('EMAIL_TRANSCRIPT.FORM.EMAIL.ERROR') }}
</span> </span>
</label> </label>
@@ -73,8 +73,10 @@
</template> </template>
<script> <script>
import { required, minLength, email } from 'vuelidate/lib/validators'; import { required, minLength, email } from '@vuelidate/validators';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import { useVuelidate } from '@vuelidate/core';
export default { export default {
mixins: [alertMixin], mixins: [alertMixin],
props: { props: {
@@ -87,6 +89,9 @@ export default {
default: () => ({}), default: () => ({}),
}, },
}, },
setup() {
return { v$: useVuelidate() };
},
data() { data() {
return { return {
email: '', email: '',
@@ -108,7 +113,7 @@ export default {
isFormValid() { isFormValid() {
if (this.selectedType) { if (this.selectedType) {
if (this.sentToOtherEmailAddress) { if (this.sentToOtherEmailAddress) {
return !!this.email && !this.$v.email.$error; return !!this.email && !this.v$.email.$error;
} }
return true; return true;
} }
@@ -1,7 +1,10 @@
<template> <template>
<li v-if="shouldRenderMessage" :id="`message${data.id}`" :class="alignBubble"> <li v-if="shouldRenderMessage" :id="`message${data.id}`" :class="alignBubble">
<div :class="wrapClass"> <div :class="wrapClass">
<div v-if="isFailed && !hasOneDayPassed" class="message-failed--alert"> <div
v-if="isFailed && !hasOneDayPassed && !isAnEmailInbox"
class="message-failed--alert"
>
<woot-button <woot-button
v-tooltip.top-end="$t('CONVERSATION.TRY_AGAIN')" v-tooltip.top-end="$t('CONVERSATION.TRY_AGAIN')"
size="tiny" size="tiny"
@@ -203,6 +206,10 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
isAnEmailInbox: {
type: Boolean,
default: false,
},
inboxSupportsReplyTo: { inboxSupportsReplyTo: {
type: Object, type: Object,
default: () => ({}), default: () => ({}),
@@ -33,6 +33,7 @@
:is-a-whatsapp-channel="isAWhatsAppChannel" :is-a-whatsapp-channel="isAWhatsAppChannel"
:is-web-widget-inbox="isAWebWidgetInbox" :is-web-widget-inbox="isAWebWidgetInbox"
:is-a-facebook-inbox="isAFacebookInbox" :is-a-facebook-inbox="isAFacebookInbox"
:is-an-email-inbox="isAnEmailChannel"
:is-instagram="isInstagramDM" :is-instagram="isInstagramDM"
:inbox-supports-reply-to="inboxSupportsReplyTo" :inbox-supports-reply-to="inboxSupportsReplyTo"
:in-reply-to="getInReplyToMessage(message)" :in-reply-to="getInReplyToMessage(message)"
@@ -164,7 +164,7 @@ import ReplyTopPanel from 'dashboard/components/widgets/WootWriter/ReplyTopPanel
import ReplyEmailHead from './ReplyEmailHead.vue'; import ReplyEmailHead from './ReplyEmailHead.vue';
import ReplyBottomPanel from 'dashboard/components/widgets/WootWriter/ReplyBottomPanel.vue'; import ReplyBottomPanel from 'dashboard/components/widgets/WootWriter/ReplyBottomPanel.vue';
import ArticleSearchPopover from 'dashboard/routes/dashboard/helpcenter/components/ArticleSearch/SearchPopover.vue'; import ArticleSearchPopover from 'dashboard/routes/dashboard/helpcenter/components/ArticleSearch/SearchPopover.vue';
import MessageSignatureMissingAlert from './MessageSignatureMissingAlert'; import MessageSignatureMissingAlert from './MessageSignatureMissingAlert.vue';
import Banner from 'dashboard/components/ui/Banner.vue'; import Banner from 'dashboard/components/ui/Banner.vue';
import { REPLY_EDITOR_MODES } from 'dashboard/components/widgets/WootWriter/constants'; import { REPLY_EDITOR_MODES } from 'dashboard/components/widgets/WootWriter/constants';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue'; import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
@@ -198,7 +198,7 @@ import {
import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage'; import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage';
import { LocalStorage } from 'shared/helpers/localStorage'; import { LocalStorage } from 'shared/helpers/localStorage';
const EmojiInput = () => import('shared/components/emoji/EmojiInput'); const EmojiInput = () => import('shared/components/emoji/EmojiInput.vue');
export default { export default {
components: { components: {
@@ -1208,6 +1208,7 @@ export default {
@apply bg-yellow-50 dark:bg-yellow-200; @apply bg-yellow-50 dark:bg-yellow-200;
} }
} }
.send-button { .send-button {
@apply mb-0; @apply mb-0;
} }
@@ -1228,6 +1229,7 @@ export default {
.emoji-dialog--rtl { .emoji-dialog--rtl {
@apply left-[unset] -right-80; @apply left-[unset] -right-80;
&::before { &::before {
transform: rotate(90deg); transform: rotate(90deg);
filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.08)); filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.08));
@@ -1,15 +1,15 @@
<template> <template>
<div> <div>
<div v-if="toEmails"> <div v-if="toEmails">
<div class="input-group small" :class="{ error: $v.toEmailsVal.$error }"> <div class="input-group small" :class="{ error: v$.toEmailsVal.$error }">
<label class="input-group-label"> <label class="input-group-label">
{{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.TO') }} {{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.TO') }}
</label> </label>
<div class="input-group-field"> <div class="input-group-field">
<woot-input <woot-input
v-model.trim="$v.toEmailsVal.$model" v-model.trim="v$.toEmailsVal.$model"
type="text" type="text"
:class="{ error: $v.toEmailsVal.$error }" :class="{ error: v$.toEmailsVal.$error }"
:placeholder="$t('CONVERSATION.REPLYBOX.EMAIL_HEAD.CC.PLACEHOLDER')" :placeholder="$t('CONVERSATION.REPLYBOX.EMAIL_HEAD.CC.PLACEHOLDER')"
@blur="onBlur" @blur="onBlur"
/> />
@@ -17,15 +17,15 @@
</div> </div>
</div> </div>
<div class="input-group-wrap"> <div class="input-group-wrap">
<div class="input-group small" :class="{ error: $v.ccEmailsVal.$error }"> <div class="input-group small" :class="{ error: v$.ccEmailsVal.$error }">
<label class="input-group-label"> <label class="input-group-label">
{{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.CC.LABEL') }} {{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.CC.LABEL') }}
</label> </label>
<div class="input-group-field"> <div class="input-group-field">
<woot-input <woot-input
v-model.trim="$v.ccEmailsVal.$model" v-model.trim="v$.ccEmailsVal.$model"
type="text" type="text"
:class="{ error: $v.ccEmailsVal.$error }" :class="{ error: v$.ccEmailsVal.$error }"
:placeholder="$t('CONVERSATION.REPLYBOX.EMAIL_HEAD.CC.PLACEHOLDER')" :placeholder="$t('CONVERSATION.REPLYBOX.EMAIL_HEAD.CC.PLACEHOLDER')"
@blur="onBlur" @blur="onBlur"
/> />
@@ -39,20 +39,20 @@
{{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.ADD_BCC') }} {{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.ADD_BCC') }}
</woot-button> </woot-button>
</div> </div>
<span v-if="$v.ccEmailsVal.$error" class="message"> <span v-if="v$.ccEmailsVal.$error" class="message">
{{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.CC.ERROR') }} {{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.CC.ERROR') }}
</span> </span>
</div> </div>
<div v-if="showBcc" class="input-group-wrap"> <div v-if="showBcc" class="input-group-wrap">
<div class="input-group small" :class="{ error: $v.bccEmailsVal.$error }"> <div class="input-group small" :class="{ error: v$.bccEmailsVal.$error }">
<label class="input-group-label"> <label class="input-group-label">
{{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.BCC.LABEL') }} {{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.BCC.LABEL') }}
</label> </label>
<div class="input-group-field"> <div class="input-group-field">
<woot-input <woot-input
v-model.trim="$v.bccEmailsVal.$model" v-model.trim="v$.bccEmailsVal.$model"
type="text" type="text"
:class="{ error: $v.bccEmailsVal.$error }" :class="{ error: v$.bccEmailsVal.$error }"
:placeholder=" :placeholder="
$t('CONVERSATION.REPLYBOX.EMAIL_HEAD.BCC.PLACEHOLDER') $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.BCC.PLACEHOLDER')
" "
@@ -60,7 +60,7 @@
/> />
</div> </div>
</div> </div>
<span v-if="$v.bccEmailsVal.$error" class="message"> <span v-if="v$.bccEmailsVal.$error" class="message">
{{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.BCC.ERROR') }} {{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.BCC.ERROR') }}
</span> </span>
</div> </div>
@@ -137,7 +137,7 @@ export default {
this.showBcc = true; this.showBcc = true;
}, },
onBlur() { onBlur() {
this.$v.$touch(); this.v$.$touch();
this.$emit('update:bccEmails', this.bccEmailsVal); this.$emit('update:bccEmails', this.bccEmailsVal);
this.$emit('update:ccEmails', this.ccEmailsVal); this.$emit('update:ccEmails', this.ccEmailsVal);
this.$emit('update:toEmails', this.toEmailsVal); this.$emit('update:toEmails', this.toEmailsVal);
@@ -149,12 +149,14 @@ export default {
.input-group-wrap .message { .input-group-wrap .message {
@apply text-sm text-red-500 dark:text-red-500; @apply text-sm text-red-500 dark:text-red-500;
} }
.input-group { .input-group {
@apply border-b border-solid border-slate-75 dark:border-slate-700 my-1; @apply border-b border-solid border-slate-75 dark:border-slate-700 my-1;
.input-group-label { .input-group-label {
@apply border-transparent bg-transparent text-xs font-semibold pl-0; @apply border-transparent bg-transparent text-xs font-semibold pl-0;
} }
.input-group-field::v-deep input { .input-group-field::v-deep input {
@apply mb-0 border-transparent; @apply mb-0 border-transparent;
} }
@@ -162,6 +164,7 @@ export default {
.input-group.error { .input-group.error {
@apply border-b-red-500 dark:border-b-red-500; @apply border-b-red-500 dark:border-b-red-500;
.input-group-label { .input-group-label {
@apply text-red-500 dark:text-red-500; @apply text-red-500 dark:text-red-500;
} }
@@ -45,7 +45,9 @@ const allKeysRequired = value => {
const keys = Object.keys(value); const keys = Object.keys(value);
return keys.every(key => value[key]); return keys.every(key => value[key]);
}; };
import { requiredIf } from 'vuelidate/lib/validators'; import { useVuelidate } from '@vuelidate/core';
import { requiredIf } from '@vuelidate/validators';
export default { export default {
props: { props: {
template: { template: {
@@ -53,6 +55,9 @@ export default {
default: () => {}, default: () => {},
}, },
}, },
setup() {
return { v$: useVuelidate() };
},
validations: { validations: {
processedParams: { processedParams: {
requiredIfKeysPresent: requiredIf('variables'), requiredIfKeysPresent: requiredIf('variables'),
@@ -149,9 +154,11 @@ footer {
@apply ml-2.5; @apply ml-2.5;
} }
} }
.error { .error {
@apply bg-red-100 dark:bg-red-100 rounded-md text-red-800 dark:text-red-800 p-2.5 text-center; @apply bg-red-100 dark:bg-red-100 rounded-md text-red-800 dark:text-red-800 p-2.5 text-center;
} }
.template-input { .template-input {
@apply bg-slate-25 dark:bg-slate-900 text-slate-700 dark:text-slate-100; @apply bg-slate-25 dark:bg-slate-900 text-slate-700 dark:text-slate-100;
} }
@@ -46,7 +46,7 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import '~dashboard/assets/scss/variables'; @import 'dashboard/assets/scss/variables';
.file { .file {
display: flex; display: flex;
@@ -1,4 +1,4 @@
import emailValidator from 'vuelidate/lib/validators/email'; import { email as emailValidator } from '@vuelidate/validators';
export const validEmailsByComma = value => { export const validEmailsByComma = value => {
if (!value.length) return true; if (!value.length) return true;
@@ -5,7 +5,7 @@
class="cursor-pointer py-2 pr-1.5 pl-2 rounded-tl-md rounded-bl-md flex items-center justify-center gap-1.5 bg-slate-25 dark:bg-slate-700 h-10 w-14" class="cursor-pointer py-2 pr-1.5 pl-2 rounded-tl-md rounded-bl-md flex items-center justify-center gap-1.5 bg-slate-25 dark:bg-slate-700 h-10 w-14"
@click="toggleCountryDropdown" @click="toggleCountryDropdown"
> >
<h5 v-if="activeCountry.emoji" class="mb-0"> <h5 v-if="activeCountry" class="mb-0">
{{ activeCountry.emoji }} {{ activeCountry.emoji }}
</h5> </h5>
<fluent-icon v-else icon="globe" class="fluent-icon" size="16" /> <fluent-icon v-else icon="globe" class="fluent-icon" size="16" />
@@ -6,12 +6,12 @@
<woot-input <woot-input
v-model="value" v-model="value"
type="text" type="text"
:class="{ error: $v.value.$error }" :class="{ error: v$.value.$error }"
:placeholder="confirmPlaceHolderText" :placeholder="confirmPlaceHolderText"
@blur="$v.value.$touch" @blur="v$.value.$touch"
/> />
<div class="button-wrapper"> <div class="button-wrapper">
<woot-button color-scheme="alert" :is-disabled="$v.value.$invalid"> <woot-button color-scheme="alert" :is-disabled="v$.value.$invalid">
{{ confirmText }} {{ confirmText }}
</woot-button> </woot-button>
<woot-button class="clear" @click.prevent="closeModal"> <woot-button class="clear" @click.prevent="closeModal">
@@ -23,14 +23,14 @@
</template> </template>
<script> <script>
import { required } from 'vuelidate/lib/validators'; import { required } from '@vuelidate/validators';
import Modal from '../../Modal.vue'; import Modal from '../../Modal.vue';
import { useVuelidate } from '@vuelidate/core';
export default { export default {
components: { components: {
Modal, Modal,
}, },
props: { props: {
show: { show: {
type: Boolean, type: Boolean,
@@ -61,6 +61,9 @@ export default {
default: '', default: '',
}, },
}, },
setup() {
return { v$: useVuelidate() };
},
data() { data() {
return { return {
value: '', value: '',
@@ -47,6 +47,8 @@ export const getCustomFields = ({ standardFields, customAttributes }) => {
type: attribute.attribute_display_type, type: attribute.attribute_display_type,
values: attribute.attribute_values, values: attribute.attribute_values,
field_type: attribute.attribute_model, field_type: attribute.attribute_model,
regex_pattern: attribute.regex_pattern,
regex_cue: attribute.regex_cue,
required: false, required: false,
enabled: false, enabled: false,
}); });
@@ -44,4 +44,18 @@ export default {
created_at: '2021-11-29T10:20:04.563Z', created_at: '2021-11-29T10:20:04.563Z',
}, },
], ],
customAttributesWithRegex: [
{
id: 2,
attribute_description: 'Test contact Attribute',
attribute_display_name: 'Test contact Attribute',
attribute_display_type: 'text',
attribute_key: 'test_contact_attribute',
attribute_model: 'contact_attribute',
attribute_values: Array(0),
created_at: '2023-09-20T10:20:04.563Z',
regex_pattern: '^w+$',
regex_cue: 'It should be a combination of alphabets and numbers',
},
],
}; };
@@ -5,7 +5,8 @@ import {
} from '../preChat'; } from '../preChat';
import inboxFixture from './inboxFixture'; import inboxFixture from './inboxFixture';
const { customFields, customAttributes } = inboxFixture; const { customFields, customAttributes, customAttributesWithRegex } =
inboxFixture;
describe('#Pre chat Helpers', () => { describe('#Pre chat Helpers', () => {
describe('getPreChatFields', () => { describe('getPreChatFields', () => {
it('should return correct pre-chat fields form options passed', () => { it('should return correct pre-chat fields form options passed', () => {
@@ -27,7 +28,6 @@ describe('#Pre chat Helpers', () => {
placeholder: 'Please enter your email address', placeholder: 'Please enter your email address',
type: 'email', type: 'email',
field_type: 'standard', field_type: 'standard',
required: false, required: false,
enabled: false, enabled: false,
}, },
@@ -71,6 +71,26 @@ describe('#Pre chat Helpers', () => {
values: [], values: [],
}, },
]); ]);
expect(
getCustomFields({
standardFields: { pre_chat_fields: customFields.pre_chat_fields },
customAttributes: customAttributesWithRegex,
})
).toEqual([
{
enabled: false,
label: 'Test contact Attribute',
placeholder: 'Test contact Attribute',
name: 'test_contact_attribute',
required: false,
field_type: 'contact_attribute',
type: 'text',
values: [],
regex_pattern: '^w+$',
regex_cue: 'It should be a combination of alphabets and numbers',
},
]);
}); });
}); });
}); });
@@ -1,18 +1,18 @@
{ {
"FILTER": { "FILTER": {
"TITLE": "Filter Conversations", "TITLE": "Filter conversations",
"SUBTITLE": "Add filters below and hit 'Apply filters' to filter conversations.", "SUBTITLE": "Add your filters below and hit 'Apply filters' to cut through the chat clutter.",
"EDIT_CUSTOM_FILTER": "Edit Folder", "EDIT_CUSTOM_FILTER": "Edit Folder",
"CUSTOM_VIEWS_SUBTITLE": "Add or remove filters and update your folder.", "CUSTOM_VIEWS_SUBTITLE": "Add or remove filters and update your folder.",
"ADD_NEW_FILTER": "Add Filter", "ADD_NEW_FILTER": "Add filter",
"FILTER_DELETE_ERROR": "You should have atleast one filter to save", "FILTER_DELETE_ERROR": "Oops, looks like we can't save nothing! Please add at least one filter to save it.",
"SUBMIT_BUTTON_LABEL": "Apply filters", "SUBMIT_BUTTON_LABEL": "Apply filters",
"UPDATE_BUTTON_LABEL": "Update folder", "UPDATE_BUTTON_LABEL": "Update folder",
"CANCEL_BUTTON_LABEL": "Cancel", "CANCEL_BUTTON_LABEL": "Cancel",
"CLEAR_BUTTON_LABEL": "Clear Filters", "CLEAR_BUTTON_LABEL": "Clear filters",
"EMPTY_VALUE_ERROR": "Value is required",
"FOLDER_LABEL": "Folder Name", "FOLDER_LABEL": "Folder Name",
"FOLDER_QUERY_LABEL": "Folder Query", "FOLDER_QUERY_LABEL": "Folder Query",
"EMPTY_VALUE_ERROR": "Value is required.",
"TOOLTIP_LABEL": "Filter conversations", "TOOLTIP_LABEL": "Filter conversations",
"QUERY_DROPDOWN_LABELS": { "QUERY_DROPDOWN_LABELS": {
"AND": "AND", "AND": "AND",
@@ -36,44 +36,44 @@
}, },
"ATTRIBUTES": { "ATTRIBUTES": {
"STATUS": "Status", "STATUS": "Status",
"ASSIGNEE_NAME": "Assignee Name", "ASSIGNEE_NAME": "Assignee name",
"INBOX_NAME": "Inbox Name", "INBOX_NAME": "Inbox name",
"TEAM_NAME": "Team Name", "TEAM_NAME": "Team name",
"CONVERSATION_IDENTIFIER": "Conversation Identifier", "CONVERSATION_IDENTIFIER": "Conversation identifier",
"CAMPAIGN_NAME": "Campaign Name", "CAMPAIGN_NAME": "Campaign name",
"LABELS": "Labels", "LABELS": "Labels",
"BROWSER_LANGUAGE": "Browser Language", "BROWSER_LANGUAGE": "Browser language",
"PRIORITY": "Priority", "PRIORITY": "Priority",
"COUNTRY_NAME": "Country Name", "COUNTRY_NAME": "Country name",
"REFERER_LINK": "Referer link", "REFERER_LINK": "Referer link",
"CUSTOM_ATTRIBUTE_LIST": "List", "CUSTOM_ATTRIBUTE_LIST": "List",
"CUSTOM_ATTRIBUTE_TEXT": "Text", "CUSTOM_ATTRIBUTE_TEXT": "Text",
"CUSTOM_ATTRIBUTE_NUMBER": "Number", "CUSTOM_ATTRIBUTE_NUMBER": "Number",
"CUSTOM_ATTRIBUTE_LINK": "Link", "CUSTOM_ATTRIBUTE_LINK": "Link",
"CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox", "CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox",
"CREATED_AT": "Created At", "CREATED_AT": "Created at",
"LAST_ACTIVITY": "Last Activity" "LAST_ACTIVITY": "Last activity"
}, },
"GROUPS": { "GROUPS": {
"STANDARD_FILTERS": "Standard Filters", "STANDARD_FILTERS": "Standard filters",
"ADDITIONAL_FILTERS": "Additional Filters", "ADDITIONAL_FILTERS": "Additional filters",
"CUSTOM_ATTRIBUTES": "Custom Attributes" "CUSTOM_ATTRIBUTES": "Custom attributes"
}, },
"CUSTOM_VIEWS": { "CUSTOM_VIEWS": {
"ADD": { "ADD": {
"TITLE": "Do you want to save this filter?", "TITLE": "Do you want to save this filter?",
"LABEL": "Name this filter", "LABEL": "Name this filter",
"PLACEHOLDER": "Enter a name for this filter", "PLACEHOLDER": "Name your filter to refer it later.",
"ERROR_MESSAGE": "Name is required", "ERROR_MESSAGE": "Name is required.",
"SAVE_BUTTON": "Save filter", "SAVE_BUTTON": "Save filter",
"CANCEL_BUTTON": "Cancel", "CANCEL_BUTTON": "Cancel",
"API_FOLDERS": { "API_FOLDERS": {
"SUCCESS_MESSAGE": "Folder created successfully", "SUCCESS_MESSAGE": "Folder created successfully.",
"ERROR_MESSAGE": "Error while creating folder" "ERROR_MESSAGE": "Error while creating folder."
}, },
"API_SEGMENTS": { "API_SEGMENTS": {
"SUCCESS_MESSAGE": "Segment created successfully", "SUCCESS_MESSAGE": "Segment created successfully.",
"ERROR_MESSAGE": "Error while creating segment" "ERROR_MESSAGE": "Error while creating segment."
} }
}, },
"EDIT": { "EDIT": {
@@ -83,19 +83,19 @@
"DELETE_BUTTON": "Delete filter", "DELETE_BUTTON": "Delete filter",
"MODAL": { "MODAL": {
"CONFIRM": { "CONFIRM": {
"TITLE": "Confirm Deletion", "TITLE": "Confirm deletion",
"MESSAGE": "Are you sure to delete the filter ", "MESSAGE": "Are you sure to delete the filter ",
"YES": "Yes, Delete", "YES": "Yes, delete",
"NO": "No, Keep it" "NO": "No, keep it"
} }
}, },
"API_FOLDERS": { "API_FOLDERS": {
"SUCCESS_MESSAGE": "Folder deleted successfully", "SUCCESS_MESSAGE": "Folder deleted successfully.",
"ERROR_MESSAGE": "Error while deleting folder" "ERROR_MESSAGE": "Error while deleting folder."
}, },
"API_SEGMENTS": { "API_SEGMENTS": {
"SUCCESS_MESSAGE": "Segment deleted successfully", "SUCCESS_MESSAGE": "Segment deleted successfully.",
"ERROR_MESSAGE": "Error while deleting segment" "ERROR_MESSAGE": "Error while deleting segment."
} }
} }
} }
@@ -1,73 +1,73 @@
{ {
"AGENT_BOTS": { "AGENT_BOTS": {
"HEADER": "Bots", "HEADER": "Bots",
"LOADING_EDITOR": "Loading Editor...", "LOADING_EDITOR": "Loading editor...",
"HEADER_BTN_TXT": "Add Bot Configuration", "HEADER_BTN_TXT": "Add bot configuration",
"SIDEBAR_TXT": "<p><b>Agent Bots</b> <p>Agent bots allows you to automate the conversations</p>", "SIDEBAR_TXT": "<p><b>Agent Bots</b> <p>Agent Bots are like the most fabulous members of your team. They can handle the small stuff, so you can focus on the stuff that matters. Give them a try.</p> <p> You can manage your bots from this page or create new ones using the 'Add bot configuraton' button.</p> <p> Open the <a href=\"https://www.chatwoot.com/hc/chatwoot-user-guide-cloud-version/articles/1677497472-how-to-use-agent-bots\" target=\"blank\">Agent bots handbook</a> in another tab for a helping hand.</p>",
"CSML_BOT_EDITOR": { "CSML_BOT_EDITOR": {
"NAME": { "NAME": {
"LABEL": "Bot Name", "LABEL": "Bot name",
"PLACEHOLDER": "Give your bot a name", "PLACEHOLDER": "Name your bot.",
"ERROR": "Bot name is required" "ERROR": "Bot name is required."
}, },
"DESCRIPTION": { "DESCRIPTION": {
"LABEL": "Bot Description", "LABEL": "Bot description",
"PLACEHOLDER": "What does this bot do?" "PLACEHOLDER": "What does this bot do?"
}, },
"BOT_CONFIG": { "BOT_CONFIG": {
"ERROR": "Please enter your CSML bot configuration above", "ERROR": "Please enter your CSML bot configuration above.",
"API_ERROR": "Your CSML configuration is invalid, please fix it and try again." "API_ERROR": "Your CSML configuration is invalid. Please fix it and try again."
}, },
"SUBMIT": "Validate and save" "SUBMIT": "Validate and save"
}, },
"BOT_CONFIGURATION": { "BOT_CONFIGURATION": {
"TITLE": "Select an agent bot", "TITLE": "Select an agent bot",
"DESC": "You can set an agent bot from the list to this inbox. The bot can initially handle the conversation and transfer it to an agent when needed.", "DESC": "Assign an Agent Bot to your inbox. They can handle initial conversations and transfer them to a live agent when necessary.",
"SUBMIT": "Update", "SUBMIT": "Update",
"DISCONNECT": "Disconnect Bot", "DISCONNECT": "Disconnect bot",
"SUCCESS_MESSAGE": "Successfully updated the agent bot", "SUCCESS_MESSAGE": "Successfully updated the agent bot.",
"DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot", "DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot.",
"ERROR_MESSAGE": "Could not update the agent bot, please try again later", "ERROR_MESSAGE": "Could not update the agent bot. Please try again.",
"DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot, please try again later", "DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot. Please try again.",
"SELECT_PLACEHOLDER": "Select Bot" "SELECT_PLACEHOLDER": "Select bot"
}, },
"ADD": { "ADD": {
"TITLE": "Configure new bot", "TITLE": "Configure new bot",
"CANCEL_BUTTON_TEXT": "Cancel", "CANCEL_BUTTON_TEXT": "Cancel",
"API": { "API": {
"SUCCESS_MESSAGE": "Bot added successfully", "SUCCESS_MESSAGE": "Bot added successfully.",
"ERROR_MESSAGE": "Could not add bot, Please try again later" "ERROR_MESSAGE": "Could not add bot. Please try again later."
} }
}, },
"LIST": { "LIST": {
"404": "No Bots found, you can create a bot by clicking the 'Configure new bot' Button ↗", "404": "No bots found. You can create a bot by clicking the 'Configure new bot' button ↗",
"LOADING": "Fetching Bots...", "LOADING": "Fetching bots...",
"TYPE": "Bot Type" "TYPE": "Bot type"
}, },
"DELETE": { "DELETE": {
"BUTTON_TEXT": "Delete", "BUTTON_TEXT": "Delete",
"TITLE": "Delete Bot", "TITLE": "Delete bot",
"SUBMIT": "Delete", "SUBMIT": "Delete",
"CANCEL_BUTTON_TEXT": "Cancel", "CANCEL_BUTTON_TEXT": "Cancel",
"DESCRIPTION": "Are you sure you want to delete this bot? This action is irreversible", "DESCRIPTION": "Are you sure you want to delete this bot? This action is irreversible.",
"API": { "API": {
"SUCCESS_MESSAGE": "Bot deleted successfully", "SUCCESS_MESSAGE": "Bot deleted successfully.",
"ERROR_MESSAGE": "Could not able to delete bot, Please try again later" "ERROR_MESSAGE": "Could not delete bot. Please try again."
} }
}, },
"EDIT": { "EDIT": {
"BUTTON_TEXT": "Edit", "BUTTON_TEXT": "Edit",
"LOADING": "Fetching Bots...", "LOADING": "Fetching bots...",
"TITLE": "Edit Bot", "TITLE": "Edit bot",
"CANCEL_BUTTON_TEXT": "Cancel", "CANCEL_BUTTON_TEXT": "Cancel",
"API": { "API": {
"SUCCESS_MESSAGE": "Bot updated successfully", "SUCCESS_MESSAGE": "Bot updated successfully.",
"ERROR_MESSAGE": "Could not update bot, Please try again later" "ERROR_MESSAGE": "Could not update bot. Please try again."
} }
}, },
"TYPES": { "TYPES": {
"WEBHOOK": "Webhook Bot", "WEBHOOK": "Webhook bot",
"CSML": "CSML Bot" "CSML": "CSML bot"
} }
} }
} }
@@ -1,40 +1,40 @@
{ {
"BULK_ACTION": { "BULK_ACTION": {
"CONVERSATIONS_SELECTED": "%{conversationCount} conversations selected", "CONVERSATIONS_SELECTED": "%{conversationCount} conversations selected",
"AGENT_SELECT_LABEL": "Select Agent", "AGENT_SELECT_LABEL": "Select agent",
"ASSIGN_CONFIRMATION_LABEL": "Are you sure to assign %{conversationCount} %{conversationLabel} to", "ASSIGN_CONFIRMATION_LABEL": "Are you sure to assign %{conversationCount} %{conversationLabel} to",
"UNASSIGN_CONFIRMATION_LABEL": "Are you sure to unassign %{conversationCount} %{conversationLabel}?", "UNASSIGN_CONFIRMATION_LABEL": "Are you sure to unassign %{conversationCount} %{conversationLabel}?",
"GO_BACK_LABEL": "Go back", "GO_BACK_LABEL": "Go back",
"ASSIGN_LABEL": "Assign", "ASSIGN_LABEL": "Assign",
"YES": "Yes", "YES": "Yes",
"ASSIGN_AGENT_TOOLTIP": "Assign Agent", "ASSIGN_AGENT_TOOLTIP": "Assign agent",
"ASSIGN_TEAM_TOOLTIP": "Assign team", "ASSIGN_TEAM_TOOLTIP": "Assign team",
"ASSIGN_SUCCESFUL": "Conversations assigned successfully", "ASSIGN_SUCCESFUL": "Conversations assigned successfully.",
"ASSIGN_FAILED": "Failed to assign conversations, please try again", "ASSIGN_FAILED": "Failed to assign conversations. Please try again.",
"RESOLVE_SUCCESFUL": "Conversations resolved successfully", "RESOLVE_SUCCESFUL": "Conversations resolved successfully.",
"RESOLVE_FAILED": "Failed to resolve conversations, please try again", "RESOLVE_FAILED": "Failed to resolve conversations. Please try again.",
"ALL_CONVERSATIONS_SELECTED_ALERT": "Conversations visible on this page are only selected.", "ALL_CONVERSATIONS_SELECTED_ALERT": "Conversations visible on this page are only selected.",
"AGENT_LIST_LOADING": "Loading Agents", "AGENT_LIST_LOADING": "Loading agents",
"UPDATE": { "UPDATE": {
"CHANGE_STATUS": "Change status", "CHANGE_STATUS": "Change status",
"SNOOZE_UNTIL_NEXT_REPLY": "Snooze until next reply", "SNOOZE_UNTIL_NEXT_REPLY": "Snooze until next reply.",
"UPDATE_SUCCESFUL": "Conversation status updated successfully.", "UPDATE_SUCCESFUL": "Conversation status updated successfully.",
"UPDATE_FAILED": "Failed to update conversations, please try again" "UPDATE_FAILED": "Failed to update conversations. Please try again."
}, },
"LABELS": { "LABELS": {
"ASSIGN_LABELS": "Assign Labels", "ASSIGN_LABELS": "Assign labels",
"NO_LABELS_FOUND": "No labels found for", "NO_LABELS_FOUND": "No labels found for",
"ASSIGN_SELECTED_LABELS": "Assign selected labels", "ASSIGN_SELECTED_LABELS": "Assign selected labels",
"ASSIGN_SUCCESFUL": "Labels assigned successfully", "ASSIGN_SUCCESFUL": "Labels assigned successfully.",
"ASSIGN_FAILED": "Failed to assign labels, please try again" "ASSIGN_FAILED": "Failed to assign labels. Please try again."
}, },
"TEAMS": { "TEAMS": {
"TEAM_SELECT_LABEL": "Select Team", "TEAM_SELECT_LABEL": "Select team",
"NONE": "None", "NONE": "None",
"NO_TEAMS_AVAILABLE": "There are no teams added to this account yet.", "NO_TEAMS_AVAILABLE": "There are no teams added to this account yet.",
"ASSIGN_SELECTED_TEAMS": "Assign selected team", "ASSIGN_SELECTED_TEAMS": "Assign selected team.",
"ASSIGN_SUCCESFUL": "Teams assiged successfully", "ASSIGN_SUCCESFUL": "Teams assiged successfully.",
"ASSIGN_FAILED": "Failed to assign team, please try again" "ASSIGN_FAILED": "Failed to assign team. Please try again."
} }
} }
} }
@@ -1,75 +1,75 @@
{ {
"CANNED_MGMT": { "CANNED_MGMT": {
"HEADER": "Canned Responses", "HEADER": "Canned Responses",
"HEADER_BTN_TXT": "Add Canned Response", "HEADER_BTN_TXT": "Add canned response",
"LOADING": "Fetching Canned Responses", "LOADING": "Fetching canned responses...",
"SEARCH_404": "There are no items matching this query", "SEARCH_404": "There are no items matching this query.",
"SIDEBAR_TXT": "<p><b>Canned Responses</b> </p><p> Canned Responses are saved reply templates which can be used to quickly send out a reply to a conversation. </p><p> For creating a Canned Response, just click on the <b>Add Canned Response</b>. You can also edit or delete an existing Canned Response by clicking on the Edit or Delete button </p><p> Canned responses are used with the help of <b>Short Codes</b>. Agents can access canned responses while on a chat by typing <b>'/'</b> followed by the short code. </p>", "SIDEBAR_TXT": "<p><b>Canned Responses</b> </p><p> Canned Responses are pre-written reply templates that help you quickly respond to a conversation. To insert a canned response during a chat, agents can type a short code preceded by a '/' character. </p><p> You can manage your canned responses from this page or create new ones using the \"Add canned response\" button.</p><p>Open the <a target=\"_blank\" href=\"https://www.chatwoot.com/hc/chatwoot-user-guide-cloud-version/articles/1677501325-how-to-create-saved-reply-templates-with-canned-responses\">Canned Responses handbook</a> in another tab for a helping hand.</p><p>Also, check out the all-new <a href=\"https://www.chatwoot.com/tools/canned-responses-library\" target=\"_blank\">Canned Responses Library</a>.</p>",
"LIST": { "LIST": {
"404": "There are no canned responses available in this account.", "404": "There are no canned responses available in this account.",
"TITLE": "Manage canned responses", "TITLE": "Manage canned responses",
"DESC": "Canned Responses are predefined reply templates which can be used to quickly send out replies to tickets.", "DESC": "Canned Responses are predefined reply templates which can be used to quickly send out replies to conversations.",
"TABLE_HEADER": [ "TABLE_HEADER": [
"Short Code", "Short code",
"Content", "Content",
"Actions" "Actions"
] ]
}, },
"ADD": { "ADD": {
"TITLE": "Add Canned Response", "TITLE": "Add canned response",
"DESC": "Canned Responses are saved reply templates which can be used to quickly send out reply to conversation.", "DESC": "Canned Responses are predefined reply templates which can be used to quickly send out replies to conversations.",
"CANCEL_BUTTON_TEXT": "Cancel", "CANCEL_BUTTON_TEXT": "Cancel",
"FORM": { "FORM": {
"SHORT_CODE": { "SHORT_CODE": {
"LABEL": "Short Code", "LABEL": "Short code",
"PLACEHOLDER": "Please enter a short code", "PLACEHOLDER": "Please enter a short code.",
"ERROR": "Short Code is required" "ERROR": "Short Code is required."
}, },
"CONTENT": { "CONTENT": {
"LABEL": "Content", "LABEL": "Message",
"PLACEHOLDER": "Please enter a content", "PLACEHOLDER": "Please write the message you want to save as a template to use later.",
"ERROR": "Content is required" "ERROR": "Message is required."
}, },
"SUBMIT": "Submit" "SUBMIT": "Submit"
}, },
"API": { "API": {
"SUCCESS_MESSAGE": "Canned Response added successfully", "SUCCESS_MESSAGE": "Canned response added successfully.",
"ERROR_MESSAGE": "Could not create canned response. Please try again later." "ERROR_MESSAGE": "Could not connect to Woot server. Please try again."
} }
}, },
"EDIT": { "EDIT": {
"TITLE": "Edit Canned Response", "TITLE": "Edit canned response",
"CANCEL_BUTTON_TEXT": "Cancel", "CANCEL_BUTTON_TEXT": "Cancel",
"FORM": { "FORM": {
"SHORT_CODE": { "SHORT_CODE": {
"LABEL": "Short Code", "LABEL": "Short code",
"PLACEHOLDER": "Please enter a shortcode", "PLACEHOLDER": "Please enter a shortcode.",
"ERROR": "Short Code is required" "ERROR": "Short code is required."
}, },
"CONTENT": { "CONTENT": {
"LABEL": "Content", "LABEL": "Message",
"PLACEHOLDER": "Please enter a content", "PLACEHOLDER": "Please write the message you want to save as a template to use later.",
"ERROR": "Content is required" "ERROR": "Message is required."
}, },
"SUBMIT": "Submit" "SUBMIT": "Submit"
}, },
"BUTTON_TEXT": "Edit", "BUTTON_TEXT": "Edit",
"API": { "API": {
"SUCCESS_MESSAGE": "Canned Response updated successfully", "SUCCESS_MESSAGE": "Canned response is updated successfully.",
"ERROR_MESSAGE": "Could not update canned response. Please try again later." "ERROR_MESSAGE": "Could not connect to Woot server. Please try again."
} }
}, },
"DELETE": { "DELETE": {
"BUTTON_TEXT": "Delete", "BUTTON_TEXT": "Delete",
"API": { "API": {
"SUCCESS_MESSAGE": "Canned response deleted successfully", "SUCCESS_MESSAGE": "Canned response deleted successfully.",
"ERROR_MESSAGE": "Could not delete canned response. Please try again later." "ERROR_MESSAGE": "Could not connect to Woot server. Please try again."
}, },
"CONFIRM": { "CONFIRM": {
"TITLE": "Confirm Deletion", "TITLE": "Confirm deletion",
"MESSAGE": "Are you sure to delete ", "MESSAGE": "Are you sure to delete ",
"YES": "Yes, Delete ", "YES": "Yes, delete ",
"NO": "No, Keep " "NO": "No, keep "
} }
} }
} }
@@ -51,18 +51,30 @@
"ACTIVE": "Last activity" "ACTIVE": "Last activity"
} }
}, },
"CHAT_SORT_FILTER_ITEMS": { "SORT_ORDER_ITEMS": {
"latest": { "last_activity_at_asc": {
"TEXT": "Last activity" "TEXT": "Last activity: Oldest first"
}, },
"sort_on_created_at": { "last_activity_at_desc": {
"TEXT": "Created at" "TEXT": "Last activity: Newest first"
}, },
"sort_on_priority": { "created_at_desc": {
"TEXT": "Priority" "TEXT": "Created at: Newest first"
}, },
"sort_on_waiting_since": { "created_at_asc": {
"TEXT": "Pending Response" "TEXT": "Created at: Oldest first"
},
"priority_desc": {
"TEXT": "Priority: Highest first"
},
"priority_asc": {
"TEXT": "Priority: Lowest first"
},
"waiting_since_asc": {
"TEXT": "Pending Response: Longest first"
},
"waiting_since_desc": {
"TEXT": "Pending Response: Shortest first"
} }
}, },
"ATTACHMENTS": { "ATTACHMENTS": {
@@ -41,6 +41,9 @@
"SAVE_CONTACT": "Save", "SAVE_CONTACT": "Save",
"UPLOADING_ATTACHMENTS": "Uploading attachments...", "UPLOADING_ATTACHMENTS": "Uploading attachments...",
"REPLIED_TO_STORY": "Replied to your story", "REPLIED_TO_STORY": "Replied to your story",
"UNSUPPORTED_MESSAGE": "This message is unsupported.",
"UNSUPPORTED_MESSAGE_FACEBOOK": "This message is unsupported. You can view this message on the Facebook Messenger app.",
"UNSUPPORTED_MESSAGE_INSTAGRAM": "This message is unsupported. You can view this message on the Instagram app.",
"SUCCESS_DELETE_MESSAGE": "Message deleted successfully", "SUCCESS_DELETE_MESSAGE": "Message deleted successfully",
"FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again", "FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again",
"NO_RESPONSE": "No response", "NO_RESPONSE": "No response",
@@ -139,6 +142,7 @@
"PRIVATE_NOTE": "Private Note", "PRIVATE_NOTE": "Private Note",
"SEND": "Send", "SEND": "Send",
"CREATE": "Add Note", "CREATE": "Add Note",
"INSERT_READ_MORE": "Read more",
"DISMISS_REPLY": "Dismiss reply", "DISMISS_REPLY": "Dismiss reply",
"REPLYING_TO": "Replying to:", "REPLYING_TO": "Replying to:",
"TIP_FORMAT_ICON": "Show rich text editor", "TIP_FORMAT_ICON": "Show rich text editor",
@@ -92,7 +92,7 @@
}, },
"NETWORK": { "NETWORK": {
"NOTIFICATION": { "NOTIFICATION": {
"TEXT": "Disconnected from Chatwoot" "OFFLINE": "Offline"
}, },
"BUTTON": { "BUTTON": {
"REFRESH": "Refresh" "REFRESH": "Refresh"
@@ -3,6 +3,7 @@
"HEADER": { "HEADER": {
"FILTER": "Filter by", "FILTER": "Filter by",
"SORT": "Sort by", "SORT": "Sort by",
"LOCALE": "Locale",
"SETTINGS_BUTTON": "Settings", "SETTINGS_BUTTON": "Settings",
"NEW_BUTTON": "New Article", "NEW_BUTTON": "New Article",
"DROPDOWN_OPTIONS": { "DROPDOWN_OPTIONS": {
@@ -15,6 +16,12 @@
"MINE": "My Articles", "MINE": "My Articles",
"DRAFT": "Draft Articles", "DRAFT": "Draft Articles",
"ARCHIVED": "Archived Articles" "ARCHIVED": "Archived Articles"
},
"LOCALE_SELECT": {
"TITLE": "Select locale",
"PLACEHOLDER": "Select locale",
"NO_RESULT": "No locale found",
"SEARCH_PLACEHOLDER": "Search locale"
} }
}, },
"EDIT_HEADER": { "EDIT_HEADER": {
@@ -76,6 +83,9 @@
}, },
"ARTICLE_SEARCH_RESULT": { "ARTICLE_SEARCH_RESULT": {
"UNCATEGORIZED": "Uncategorized", "UNCATEGORIZED": "Uncategorized",
"SEARCH_RESULTS": "Search results for %{query}",
"EMPTY_TEXT": "Search for articles to insert into replies.",
"SEARCH_LOADER": "Searching...",
"INSERT_ARTICLE": "Insert", "INSERT_ARTICLE": "Insert",
"NO_RESULT": "No articles found", "NO_RESULT": "No articles found",
"COPY_LINK": "Copy article link to clipboard", "COPY_LINK": "Copy article link to clipboard",
@@ -220,7 +230,10 @@
"LOGO": { "LOGO": {
"LABEL": "Logo", "LABEL": "Logo",
"UPLOAD_BUTTON": "Upload logo", "UPLOAD_BUTTON": "Upload logo",
"HELP_TEXT": "This logo will be displayed on the portal header." "HELP_TEXT": "This logo will be displayed on the portal header.",
"IMAGE_UPLOAD_SUCCESS": "Logo uploaded successfully",
"IMAGE_UPLOAD_ERROR": "Logo deleted successfully",
"IMAGE_DELETE_ERROR": "Error while deleting logo"
}, },
"NAME": { "NAME": {
"LABEL": "Name", "LABEL": "Name",
@@ -426,6 +439,21 @@
} }
} }
}, },
"ARTICLE_SEARCH": {
"TITLE": "Search articles",
"PLACEHOLDER": "Search articles",
"NO_RESULT": "No articles found",
"SEARCHING": "Searching...",
"SEARCH_BUTTON": "Search",
"INSERT_ARTICLE": "Insert link",
"IFRAME_ERROR": "URL is empty or invalid. Unable to display content.",
"OPEN_ARTICLE_SEARCH": "Insert article from Help Center",
"SUCCESS_ARTICLE_INSERTED": "Article inserted successfully",
"PREVIEW_LINK": "Preview article",
"CANCEL": "Close",
"BACK": "Back",
"BACK_RESULTS": "Back to results"
},
"UPGRADE_PAGE": { "UPGRADE_PAGE": {
"TITLE": "Help Center", "TITLE": "Help Center",
"DESCRIPTION": "Create user-friendly self-service portals. Help your users to access the articles and get support 24/7. Upgrade your subscription to enable this feature.", "DESCRIPTION": "Create user-friendly self-service portals. Help your users to access the articles and get support 24/7. Upgrade your subscription to enable this feature.",
@@ -1,18 +1,18 @@
{ {
"FILTER": { "FILTER": {
"TITLE": "تصفية المحادثات", "TITLE": "تصفية المحادثات",
"SUBTITLE": "إضافة فلاتر أدناه واضغط على 'إرسال' لتصفية المحادثات.", "SUBTITLE": "Add your filters below and hit 'Apply filters' to cut through the chat clutter.",
"EDIT_CUSTOM_FILTER": "Edit Folder", "EDIT_CUSTOM_FILTER": "Edit Folder",
"CUSTOM_VIEWS_SUBTITLE": "Add or remove filters and update your folder.", "CUSTOM_VIEWS_SUBTITLE": "Add or remove filters and update your folder.",
"ADD_NEW_FILTER": "إضافة عامل تصفية", "ADD_NEW_FILTER": "Add filter",
"FILTER_DELETE_ERROR": "يجب أن يكون لديك عامل تصفية واحد على الأقل للحفظ", "FILTER_DELETE_ERROR": "Oops, looks like we can't save nothing! Please add at least one filter to save it.",
"SUBMIT_BUTTON_LABEL": "تطبيق عامل التصفية", "SUBMIT_BUTTON_LABEL": "تطبيق عامل التصفية",
"UPDATE_BUTTON_LABEL": "Update folder", "UPDATE_BUTTON_LABEL": "Update folder",
"CANCEL_BUTTON_LABEL": "إلغاء", "CANCEL_BUTTON_LABEL": "إلغاء",
"CLEAR_BUTTON_LABEL": "مسح عامل التصفية", "CLEAR_BUTTON_LABEL": "Clear filters",
"EMPTY_VALUE_ERROR": "القيمة مطلوبة",
"FOLDER_LABEL": "Folder Name", "FOLDER_LABEL": "Folder Name",
"FOLDER_QUERY_LABEL": "Folder Query", "FOLDER_QUERY_LABEL": "Folder Query",
"EMPTY_VALUE_ERROR": "القيمة مطلوبة.",
"TOOLTIP_LABEL": "تصفية المحادثات", "TOOLTIP_LABEL": "تصفية المحادثات",
"QUERY_DROPDOWN_LABELS": { "QUERY_DROPDOWN_LABELS": {
"AND": "و", "AND": "و",
@@ -36,15 +36,15 @@
}, },
"ATTRIBUTES": { "ATTRIBUTES": {
"STATUS": "الحالة", "STATUS": "الحالة",
"ASSIGNEE_NAME": "اسم المحال إليه", "ASSIGNEE_NAME": "Assignee name",
"INBOX_NAME": "اسم صندوق الوارد لقناة التواصل", "INBOX_NAME": "اسم صندوق الوارد",
"TEAM_NAME": "اسم الفريق", "TEAM_NAME": "اسم الفريق",
"CONVERSATION_IDENTIFIER": "معرف المحادثة", "CONVERSATION_IDENTIFIER": "Conversation identifier",
"CAMPAIGN_NAME": "اسم الحملة", "CAMPAIGN_NAME": "Campaign name",
"LABELS": "الوسوم", "LABELS": "الوسوم",
"BROWSER_LANGUAGE": "لغة المتصفح", "BROWSER_LANGUAGE": "Browser language",
"PRIORITY": "الأولوية", "PRIORITY": "الأولوية",
"COUNTRY_NAME": "اسم الدولة", "COUNTRY_NAME": "Country name",
"REFERER_LINK": "رابط المرجع", "REFERER_LINK": "رابط المرجع",
"CUSTOM_ATTRIBUTE_LIST": "القائمة", "CUSTOM_ATTRIBUTE_LIST": "القائمة",
"CUSTOM_ATTRIBUTE_TEXT": "النص", "CUSTOM_ATTRIBUTE_TEXT": "النص",
@@ -52,28 +52,28 @@
"CUSTOM_ATTRIBUTE_LINK": "الرابط", "CUSTOM_ATTRIBUTE_LINK": "الرابط",
"CUSTOM_ATTRIBUTE_CHECKBOX": "مربع", "CUSTOM_ATTRIBUTE_CHECKBOX": "مربع",
"CREATED_AT": "تم إنشاؤها في", "CREATED_AT": "تم إنشاؤها في",
"LAST_ACTIVITY": "آخر نشاط" "LAST_ACTIVITY": "النشاط الأخير"
}, },
"GROUPS": { "GROUPS": {
"STANDARD_FILTERS": "الفلاتر القياسية", "STANDARD_FILTERS": "Standard filters",
"ADDITIONAL_FILTERS": "فلاتر إضافية", "ADDITIONAL_FILTERS": "Additional filters",
"CUSTOM_ATTRIBUTES": "سمات مخصصة" "CUSTOM_ATTRIBUTES": "Custom attributes"
}, },
"CUSTOM_VIEWS": { "CUSTOM_VIEWS": {
"ADD": { "ADD": {
"TITLE": "هل تريد حفظ هذا الفلتر؟", "TITLE": "هل تريد حفظ هذا الفلتر؟",
"LABEL": "تسمية هذا الفلتر", "LABEL": "تسمية هذا الفلتر",
"PLACEHOLDER": "أدخل اسم لهذا الفلتر", "PLACEHOLDER": "Name your filter to refer it later.",
"ERROR_MESSAGE": "الاسم مطلوب", "ERROR_MESSAGE": "الاسم مطلوب.",
"SAVE_BUTTON": "حفظ الفلتر", "SAVE_BUTTON": "حفظ الفلتر",
"CANCEL_BUTTON": "إلغاء", "CANCEL_BUTTON": "إلغاء",
"API_FOLDERS": { "API_FOLDERS": {
"SUCCESS_MESSAGE": "تم إنشاء طريقة عرض مخصصة بنجاح", "SUCCESS_MESSAGE": "تم إنشاء طريقة عرض مخصصة بنجاح.",
"ERROR_MESSAGE": "خطأ أثناء إنشاء طريقة عرض مخصصة" "ERROR_MESSAGE": "خطأ أثناء إنشاء طريقة عرض مخصصة."
}, },
"API_SEGMENTS": { "API_SEGMENTS": {
"SUCCESS_MESSAGE": "تم إنشاء طريقة عرض مخصصة بنجاح", "SUCCESS_MESSAGE": "تم إنشاء طريقة عرض مخصصة بنجاح.",
"ERROR_MESSAGE": "خطأ أثناء إنشاء طريقة عرض مخصصة" "ERROR_MESSAGE": "خطأ أثناء إنشاء طريقة عرض مخصصة."
} }
}, },
"EDIT": { "EDIT": {
@@ -85,17 +85,17 @@
"CONFIRM": { "CONFIRM": {
"TITLE": "تأكيد الحذف", "TITLE": "تأكيد الحذف",
"MESSAGE": "هل أنت متأكد من حذف الفلتر ", "MESSAGE": "هل أنت متأكد من حذف الفلتر ",
"YES": "نعم، احذف", "YES": "Yes, delete",
"NO": "لا، احتفظ به" "NO": "لا، احتفظ به"
} }
}, },
"API_FOLDERS": { "API_FOLDERS": {
"SUCCESS_MESSAGE": "تم حذف طريقة عرض مخصصة بنجاح", "SUCCESS_MESSAGE": "تم حذف طريقة عرض مخصصة بنجاح.",
"ERROR_MESSAGE": "حدث خطأ أثناء حذف المجلد" "ERROR_MESSAGE": "حدث خطأ أثناء حذف المجلد."
}, },
"API_SEGMENTS": { "API_SEGMENTS": {
"SUCCESS_MESSAGE": "تم حذف العرض المخصص بنجاح", "SUCCESS_MESSAGE": "تم حذف العرض المخصص بنجاح.",
"ERROR_MESSAGE": "حدث خطأ أثناء حذف طريقة عرض مخصصة" "ERROR_MESSAGE": "حدث خطأ أثناء حذف طريقة عرض مخصصة."
} }
} }
} }
@@ -1,73 +1,73 @@
{ {
"AGENT_BOTS": { "AGENT_BOTS": {
"HEADER": "Bots", "HEADER": "Bots",
"LOADING_EDITOR": "Loading Editor...", "LOADING_EDITOR": "Loading editor...",
"HEADER_BTN_TXT": "Add Bot Configuration", "HEADER_BTN_TXT": "Add bot configuration",
"SIDEBAR_TXT": "<p><b>Agent Bots</b> <p>Agent bots allows you to automate the conversations</p>", "SIDEBAR_TXT": "<p><b>Agent Bots</b> <p>Agent Bots are like the most fabulous members of your team. They can handle the small stuff, so you can focus on the stuff that matters. Give them a try.</p> <p> You can manage your bots from this page or create new ones using the 'Add bot configuraton' button.</p> <p> Open the <a href=\"https://www.chatwoot.com/hc/chatwoot-user-guide-cloud-version/articles/1677497472-how-to-use-agent-bots\" target=\"blank\">Agent bots handbook</a> in another tab for a helping hand.</p>",
"CSML_BOT_EDITOR": { "CSML_BOT_EDITOR": {
"NAME": { "NAME": {
"LABEL": "Bot Name", "LABEL": "Bot name",
"PLACEHOLDER": "Give your bot a name", "PLACEHOLDER": "Name your bot.",
"ERROR": "Bot name is required" "ERROR": "Bot name is required."
}, },
"DESCRIPTION": { "DESCRIPTION": {
"LABEL": "Bot Description", "LABEL": "Bot description",
"PLACEHOLDER": "What does this bot do?" "PLACEHOLDER": "What does this bot do?"
}, },
"BOT_CONFIG": { "BOT_CONFIG": {
"ERROR": "Please enter your CSML bot configuration above", "ERROR": "Please enter your CSML bot configuration above.",
"API_ERROR": "Your CSML configuration is invalid, please fix it and try again." "API_ERROR": "Your CSML configuration is invalid. Please fix it and try again."
}, },
"SUBMIT": "Validate and save" "SUBMIT": "Validate and save"
}, },
"BOT_CONFIGURATION": { "BOT_CONFIGURATION": {
"TITLE": "Select an agent bot", "TITLE": "Select an agent bot",
"DESC": "You can set an agent bot from the list to this inbox. The bot can initially handle the conversation and transfer it to an agent when needed.", "DESC": "Assign an Agent Bot to your inbox. They can handle initial conversations and transfer them to a live agent when necessary.",
"SUBMIT": "تحديث", "SUBMIT": "تحديث",
"DISCONNECT": "Disconnect Bot", "DISCONNECT": "Disconnect bot",
"SUCCESS_MESSAGE": "Successfully updated the agent bot", "SUCCESS_MESSAGE": "Successfully updated the agent bot.",
"DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot", "DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot.",
"ERROR_MESSAGE": "Could not update the agent bot, please try again later", "ERROR_MESSAGE": "Could not update the agent bot. Please try again.",
"DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot, please try again later", "DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot. Please try again.",
"SELECT_PLACEHOLDER": "Select Bot" "SELECT_PLACEHOLDER": "Select bot"
}, },
"ADD": { "ADD": {
"TITLE": "Configure new bot", "TITLE": "Configure new bot",
"CANCEL_BUTTON_TEXT": "إلغاء", "CANCEL_BUTTON_TEXT": "إلغاء",
"API": { "API": {
"SUCCESS_MESSAGE": "Bot added successfully", "SUCCESS_MESSAGE": "Bot added successfully.",
"ERROR_MESSAGE": "Could not add bot, Please try again later" "ERROR_MESSAGE": "Could not add bot. Please try again later."
} }
}, },
"LIST": { "LIST": {
"404": "No Bots found, you can create a bot by clicking the 'Configure new bot' Button ↗", "404": "No bots found. You can create a bot by clicking the 'Configure new bot' button ↗",
"LOADING": "Fetching Bots...", "LOADING": "Fetching bots...",
"TYPE": "Bot Type" "TYPE": "Bot type"
}, },
"DELETE": { "DELETE": {
"BUTTON_TEXT": "حذف", "BUTTON_TEXT": "حذف",
"TITLE": "Delete Bot", "TITLE": "Delete bot",
"SUBMIT": "حذف", "SUBMIT": "حذف",
"CANCEL_BUTTON_TEXT": "إلغاء", "CANCEL_BUTTON_TEXT": "إلغاء",
"DESCRIPTION": "Are you sure you want to delete this bot? This action is irreversible", "DESCRIPTION": "Are you sure you want to delete this bot? This action is irreversible.",
"API": { "API": {
"SUCCESS_MESSAGE": "Bot deleted successfully", "SUCCESS_MESSAGE": "Bot deleted successfully.",
"ERROR_MESSAGE": "Could not able to delete bot, Please try again later" "ERROR_MESSAGE": "Could not delete bot. Please try again."
} }
}, },
"EDIT": { "EDIT": {
"BUTTON_TEXT": "تعديل", "BUTTON_TEXT": "تعديل",
"LOADING": "Fetching Bots...", "LOADING": "Fetching bots...",
"TITLE": "Edit Bot", "TITLE": "Edit bot",
"CANCEL_BUTTON_TEXT": "إلغاء", "CANCEL_BUTTON_TEXT": "إلغاء",
"API": { "API": {
"SUCCESS_MESSAGE": "Bot updated successfully", "SUCCESS_MESSAGE": "Bot updated successfully.",
"ERROR_MESSAGE": "Could not update bot, Please try again later" "ERROR_MESSAGE": "Could not update bot. Please try again."
} }
}, },
"TYPES": { "TYPES": {
"WEBHOOK": "Webhook Bot", "WEBHOOK": "Webhook bot",
"CSML": "CSML Bot" "CSML": "CSML bot"
} }
} }
} }
@@ -7,34 +7,34 @@
"GO_BACK_LABEL": "العودة للخلف", "GO_BACK_LABEL": "العودة للخلف",
"ASSIGN_LABEL": "تكليف", "ASSIGN_LABEL": "تكليف",
"YES": "نعم", "YES": "نعم",
"ASSIGN_AGENT_TOOLTIP": "إسناد وكيل", "ASSIGN_AGENT_TOOLTIP": "تعيين وكيل",
"ASSIGN_TEAM_TOOLTIP": "تعيين فريق", "ASSIGN_TEAM_TOOLTIP": "تعيين فريق",
"ASSIGN_SUCCESFUL": "تم تعيين المحادثات بنجاح", "ASSIGN_SUCCESFUL": "تم تعيين المحادثات بنجاح.",
"ASSIGN_FAILED": "فشل في تعيين المحادثات، الرجاء المحاولة مرة أخرى", "ASSIGN_FAILED": "Failed to assign conversations. Please try again.",
"RESOLVE_SUCCESFUL": "تم تسوية المحادثات بنجاح", "RESOLVE_SUCCESFUL": "تم تسوية المحادثات بنجاح.",
"RESOLVE_FAILED": "فشل في حل المحادثات، يرجى المحاولة مرة أخرى", "RESOLVE_FAILED": "Failed to resolve conversations. Please try again.",
"ALL_CONVERSATIONS_SELECTED_ALERT": "المحادثات المرئية في هذه الصفحة هي المحددة فقط.", "ALL_CONVERSATIONS_SELECTED_ALERT": "المحادثات المرئية في هذه الصفحة هي المحددة فقط.",
"AGENT_LIST_LOADING": "تحميل الوكلاء", "AGENT_LIST_LOADING": "جاري تحميل الوكلاء",
"UPDATE": { "UPDATE": {
"CHANGE_STATUS": "تغيير الحالة", "CHANGE_STATUS": "تغيير الحالة",
"SNOOZE_UNTIL_NEXT_REPLY": "غفوة حتى الرد القادم", "SNOOZE_UNTIL_NEXT_REPLY": "غفوة حتى الرد القادم.",
"UPDATE_SUCCESFUL": "تم تحديث حالة المحادثة بنجاح.", "UPDATE_SUCCESFUL": "تم تحديث حالة المحادثة بنجاح.",
"UPDATE_FAILED": "فشل تحديث المحادثات، الرجاء المحاولة مرة أخرى" "UPDATE_FAILED": "Failed to update conversations. Please try again."
}, },
"LABELS": { "LABELS": {
"ASSIGN_LABELS": "تعيين التسميات", "ASSIGN_LABELS": "Assign labels",
"NO_LABELS_FOUND": "لم يتم العثور على تسميات لـ", "NO_LABELS_FOUND": "لم يتم العثور على تسميات لـ",
"ASSIGN_SELECTED_LABELS": "تعيين التسميات المحددة", "ASSIGN_SELECTED_LABELS": "تعيين التسميات المحددة",
"ASSIGN_SUCCESFUL": "تم تعيين التسميات بنجاح", "ASSIGN_SUCCESFUL": "تم تعيين التسميات بنجاح.",
"ASSIGN_FAILED": "فشل في تعيين التسميات ، الرجاء المحاولة مرة أخرى" "ASSIGN_FAILED": "Failed to assign labels. Please try again."
}, },
"TEAMS": { "TEAMS": {
"TEAM_SELECT_LABEL": "اختيار فريق", "TEAM_SELECT_LABEL": "اختيار فريق",
"NONE": "لا شيء", "NONE": "لا شيء",
"NO_TEAMS_AVAILABLE": "لا توجد فرق مضافة إلى هذا الحساب حتى الآن.", "NO_TEAMS_AVAILABLE": "لا توجد فرق مضافة إلى هذا الحساب حتى الآن.",
"ASSIGN_SELECTED_TEAMS": "تعيين فريق محدد", "ASSIGN_SELECTED_TEAMS": "تعيين فريق محدد.",
"ASSIGN_SUCCESFUL": "تم تعيين الفرق بنجاح", "ASSIGN_SUCCESFUL": "تم تعيين الفرق بنجاح.",
"ASSIGN_FAILED": "فشل تعيين الفريق، الرجاء المحاولة مرة أخرى" "ASSIGN_FAILED": "Failed to assign team. Please try again."
} }
} }
} }
@@ -1,75 +1,75 @@
{ {
"CANNED_MGMT": { "CANNED_MGMT": {
"HEADER": "الردود السريعة", "HEADER": "الردود السريعة",
"HEADER_BTN_TXT": "إضافة رد جاهز", "HEADER_BTN_TXT": "Add canned response",
"LOADING": "جاري جلب الردود الجاهزة", "LOADING": "Fetching canned responses...",
"SEARCH_404": "لا توجد عناصر مطابقة لهذا الاستعلام", "SEARCH_404": "لا توجد عناصر مطابقة لهذا الاستعلام.",
"SIDEBAR_TXT": "<p><b>الردود الجاهزة</b> </p><p> الردود الجاهزة هي عبارة عن قوالب يتم إعدادها مسبقاً لاستخدامها في كتابة الرسائل والردود للإجابة على اكثر الاسئلة شيوعاً. </p><p> لإضافة قالب جديد، فقط انقر على <b>إضافة رد جاهز</b>. يمكنك أيضاً تعديل أو حذف الردود الجاهزة الأخرى بالنقر على زر التحرير أو الحذف </p><p> يتم تسهيل استخدام الردود المسبقة بواسطة <b>رموز مختصرة</b> لتسريع البحث والوصول إليها. يمكن للموظفين الوصول إلى قوالب الردود الجاهزة أثناء الدردشة عن طريق الضغط على زر <b>'/'</b> ومن ثم الاختصار الخاص بالقالب المراد إدخاله في مربع النص. </p>", "SIDEBAR_TXT": "<p><b>Canned Responses</b> </p><p> Canned Responses are pre-written reply templates that help you quickly respond to a conversation. To insert a canned response during a chat, agents can type a short code preceded by a '/' character. </p><p> You can manage your canned responses from this page or create new ones using the \"Add canned response\" button.</p><p>Open the <a target=\"_blank\" href=\"https://www.chatwoot.com/hc/chatwoot-user-guide-cloud-version/articles/1677501325-how-to-create-saved-reply-templates-with-canned-responses\">Canned Responses handbook</a> in another tab for a helping hand.</p><p>Also, check out the all-new <a href=\"https://www.chatwoot.com/tools/canned-responses-library\" target=\"_blank\">Canned Responses Library</a>.</p>",
"LIST": { "LIST": {
"404": "لا توجد ردود جاهزة متوفرة في هذا الحساب.", "404": "لا توجد ردود جاهزة متوفرة في هذا الحساب.",
"TITLE": "إدارة الردود الجاهزة", "TITLE": "إدارة الردود الجاهزة",
"DESC": "الردود الجاهزة هي قوالب رسائل معدة مسبقاً يمكن استخدامها لتسريع كتابة الردود في المحادثات.", "DESC": "Canned Responses are predefined reply templates which can be used to quickly send out replies to conversations.",
"TABLE_HEADER": [ "TABLE_HEADER": [
"الرمز المختصر", "Short code",
"المحتوى", "المحتوى",
"الإجراءات" "الإجراءات"
] ]
}, },
"ADD": { "ADD": {
"TITLE": "إضافة رد جاهز", "TITLE": "Add canned response",
"DESC": "الردود الجاهزة هي قوالب رسائل معدة مسبقاً يمكن استخدامها لتسريع كتابة الردود في المحادثات.", "DESC": "Canned Responses are predefined reply templates which can be used to quickly send out replies to conversations.",
"CANCEL_BUTTON_TEXT": "إلغاء", "CANCEL_BUTTON_TEXT": "إلغاء",
"FORM": { "FORM": {
"SHORT_CODE": { "SHORT_CODE": {
"LABEL": "الرمز المختصر", "LABEL": "Short code",
"PLACEHOLDER": "الرجاء إدخال رمز مختصر", "PLACEHOLDER": "Please enter a short code.",
"ERROR": "الرمز المختصر مطلوب" "ERROR": "Short Code is required."
}, },
"CONTENT": { "CONTENT": {
"LABEL": "المحتوى", "LABEL": "رسالة",
"PLACEHOLDER": "الرجاء إدخال محتوى", "PLACEHOLDER": "Please write the message you want to save as a template to use later.",
"ERROR": "المحتوى مطلوب" "ERROR": "Message is required."
}, },
"SUBMIT": "إرسال" "SUBMIT": "إرسال"
}, },
"API": { "API": {
"SUCCESS_MESSAGE": "تم إضافة قالب الرد الجاهز بنجاح", "SUCCESS_MESSAGE": "Canned response added successfully.",
"ERROR_MESSAGE": "تعذر الاتصال بالخادم، الرجاء المحاولة مرة أخرى لاحقاً" "ERROR_MESSAGE": "تعذر الاتصال بالخادم، الرجاء المحاولة مرة أخرى لاحقاً"
} }
}, },
"EDIT": { "EDIT": {
"TITLE": "تعديل قالب الرد الجاهز", "TITLE": "Edit canned response",
"CANCEL_BUTTON_TEXT": "إلغاء", "CANCEL_BUTTON_TEXT": "إلغاء",
"FORM": { "FORM": {
"SHORT_CODE": { "SHORT_CODE": {
"LABEL": "الرمز المختصر", "LABEL": "Short code",
"PLACEHOLDER": "الرجاء إدخال رمز مختصر", "PLACEHOLDER": "Please enter a shortcode.",
"ERROR": "الرمز المختصر مطلوب" "ERROR": "Short code is required."
}, },
"CONTENT": { "CONTENT": {
"LABEL": "المحتوى", "LABEL": "رسالة",
"PLACEHOLDER": "الرجاء إدخال محتوى", "PLACEHOLDER": "Please write the message you want to save as a template to use later.",
"ERROR": "المحتوى مطلوب" "ERROR": "الرسالة مطلوبة."
}, },
"SUBMIT": "إرسال" "SUBMIT": "إرسال"
}, },
"BUTTON_TEXT": "تعديل", "BUTTON_TEXT": "تعديل",
"API": { "API": {
"SUCCESS_MESSAGE": "تم تحديث قالب الرد الجاهز بنجاح", "SUCCESS_MESSAGE": "Canned response is updated successfully.",
"ERROR_MESSAGE": "تعذر الاتصال بالخادم، الرجاء المحاولة مرة أخرى لاحقاً" "ERROR_MESSAGE": "تعذر الاتصال بالخادم، الرجاء المحاولة مرة أخرى لاحقاً"
} }
}, },
"DELETE": { "DELETE": {
"BUTTON_TEXT": "حذف", "BUTTON_TEXT": "حذف",
"API": { "API": {
"SUCCESS_MESSAGE": "تم حذف قالب الرد الجاهز بنجاح", "SUCCESS_MESSAGE": "Canned response deleted successfully.",
"ERROR_MESSAGE": "تعذر الاتصال بالخادم، الرجاء المحاولة مرة أخرى لاحقاً" "ERROR_MESSAGE": "تعذر الاتصال بالخادم، الرجاء المحاولة مرة أخرى لاحقاً"
}, },
"CONFIRM": { "CONFIRM": {
"TITLE": "تأكيد الحذف", "TITLE": "تأكيد الحذف",
"MESSAGE": "هل أنت متأكد من الحذف ", "MESSAGE": "هل أنت متأكد من الحذف ",
"YES": "نعم، احذف ", "YES": "Yes, delete ",
"NO": "لا، احتفظ " "NO": "No, keep "
} }
} }
} }
@@ -51,18 +51,30 @@
"ACTIVE": "النشاط الأخير" "ACTIVE": "النشاط الأخير"
} }
}, },
"CHAT_SORT_FILTER_ITEMS": { "SORT_ORDER_ITEMS": {
"latest": { "last_activity_at_asc": {
"TEXT": "النشاط الأخير" "TEXT": "Last activity: Oldest first"
}, },
"sort_on_created_at": { "last_activity_at_desc": {
"TEXT": "تم إنشاؤها في" "TEXT": "Last activity: Newest first"
}, },
"sort_on_priority": { "created_at_desc": {
"TEXT": "الأولوية" "TEXT": "Created at: Newest first"
}, },
"sort_on_waiting_since": { "created_at_asc": {
"TEXT": "Pending Response" "TEXT": "Created at: Oldest first"
},
"priority_desc": {
"TEXT": "Priority: Highest first"
},
"priority_asc": {
"TEXT": "Priority: Lowest first"
},
"waiting_since_asc": {
"TEXT": "Pending Response: Longest first"
},
"waiting_since_desc": {
"TEXT": "Pending Response: Shortest first"
} }
}, },
"ATTACHMENTS": { "ATTACHMENTS": {
@@ -41,6 +41,9 @@
"SAVE_CONTACT": "حفظ", "SAVE_CONTACT": "حفظ",
"UPLOADING_ATTACHMENTS": "جاري تحميل المرفقات...", "UPLOADING_ATTACHMENTS": "جاري تحميل المرفقات...",
"REPLIED_TO_STORY": "Replied to your story", "REPLIED_TO_STORY": "Replied to your story",
"UNSUPPORTED_MESSAGE": "This message is unsupported.",
"UNSUPPORTED_MESSAGE_FACEBOOK": "This message is unsupported. You can view this message on the Facebook Messenger app.",
"UNSUPPORTED_MESSAGE_INSTAGRAM": "This message is unsupported. You can view this message on the Instagram app.",
"SUCCESS_DELETE_MESSAGE": "تم حذف الرسالة بنجاح", "SUCCESS_DELETE_MESSAGE": "تم حذف الرسالة بنجاح",
"FAIL_DELETE_MESSSAGE": "تعذر حذف الرسالة! حاول مرة أخرى", "FAIL_DELETE_MESSSAGE": "تعذر حذف الرسالة! حاول مرة أخرى",
"NO_RESPONSE": "لا توجد استجابة", "NO_RESPONSE": "لا توجد استجابة",
@@ -139,6 +142,7 @@
"PRIVATE_NOTE": "إضافة ملاحظة خاصة", "PRIVATE_NOTE": "إضافة ملاحظة خاصة",
"SEND": "إرسال", "SEND": "إرسال",
"CREATE": "إضافة ملاحظة", "CREATE": "إضافة ملاحظة",
"INSERT_READ_MORE": "Read more",
"DISMISS_REPLY": "Dismiss reply", "DISMISS_REPLY": "Dismiss reply",
"REPLYING_TO": "Replying to:", "REPLYING_TO": "Replying to:",
"TIP_FORMAT_ICON": "عرض محرر النصوص", "TIP_FORMAT_ICON": "عرض محرر النصوص",
@@ -92,7 +92,7 @@
}, },
"NETWORK": { "NETWORK": {
"NOTIFICATION": { "NOTIFICATION": {
"TEXT": "قطع الاتصال من Chatwoot" "OFFLINE": "غير متصل"
}, },
"BUTTON": { "BUTTON": {
"REFRESH": "تحديث" "REFRESH": "تحديث"
@@ -3,6 +3,7 @@
"HEADER": { "HEADER": {
"FILTER": "تصفية حسب", "FILTER": "تصفية حسب",
"SORT": "ترتيب حسب", "SORT": "ترتيب حسب",
"LOCALE": "اللغة",
"SETTINGS_BUTTON": "الإعدادات", "SETTINGS_BUTTON": "الإعدادات",
"NEW_BUTTON": "مقالة جديدة", "NEW_BUTTON": "مقالة جديدة",
"DROPDOWN_OPTIONS": { "DROPDOWN_OPTIONS": {
@@ -15,6 +16,12 @@
"MINE": "مقالاتي", "MINE": "مقالاتي",
"DRAFT": "مقالات مسودة", "DRAFT": "مقالات مسودة",
"ARCHIVED": "المقالات المؤرشفة" "ARCHIVED": "المقالات المؤرشفة"
},
"LOCALE_SELECT": {
"TITLE": "Select locale",
"PLACEHOLDER": "Select locale",
"NO_RESULT": "No locale found",
"SEARCH_PLACEHOLDER": "Search locale"
} }
}, },
"EDIT_HEADER": { "EDIT_HEADER": {
@@ -76,6 +83,9 @@
}, },
"ARTICLE_SEARCH_RESULT": { "ARTICLE_SEARCH_RESULT": {
"UNCATEGORIZED": "Uncategorized", "UNCATEGORIZED": "Uncategorized",
"SEARCH_RESULTS": "Search results for %{query}",
"EMPTY_TEXT": "Search for articles to insert into replies.",
"SEARCH_LOADER": "يبحث...",
"INSERT_ARTICLE": "Insert", "INSERT_ARTICLE": "Insert",
"NO_RESULT": "No articles found", "NO_RESULT": "No articles found",
"COPY_LINK": "Copy article link to clipboard", "COPY_LINK": "Copy article link to clipboard",
@@ -220,7 +230,10 @@
"LOGO": { "LOGO": {
"LABEL": "Logo", "LABEL": "Logo",
"UPLOAD_BUTTON": "Upload logo", "UPLOAD_BUTTON": "Upload logo",
"HELP_TEXT": "This logo will be displayed on the portal header." "HELP_TEXT": "This logo will be displayed on the portal header.",
"IMAGE_UPLOAD_SUCCESS": "Logo uploaded successfully",
"IMAGE_UPLOAD_ERROR": "Logo deleted successfully",
"IMAGE_DELETE_ERROR": "Error while deleting logo"
}, },
"NAME": { "NAME": {
"LABEL": "الاسم", "LABEL": "الاسم",
@@ -426,6 +439,21 @@
} }
} }
}, },
"ARTICLE_SEARCH": {
"TITLE": "Search articles",
"PLACEHOLDER": "Search articles",
"NO_RESULT": "No articles found",
"SEARCHING": "يبحث...",
"SEARCH_BUTTON": "بحث",
"INSERT_ARTICLE": "Insert link",
"IFRAME_ERROR": "URL is empty or invalid. Unable to display content.",
"OPEN_ARTICLE_SEARCH": "Insert article from Help Center",
"SUCCESS_ARTICLE_INSERTED": "Article inserted successfully",
"PREVIEW_LINK": "Preview article",
"CANCEL": "أغلق",
"BACK": "العودة",
"BACK_RESULTS": "Back to results"
},
"UPGRADE_PAGE": { "UPGRADE_PAGE": {
"TITLE": "Help Center", "TITLE": "Help Center",
"DESCRIPTION": "Create user-friendly self-service portals. Help your users to access the articles and get support 24/7. Upgrade your subscription to enable this feature.", "DESCRIPTION": "Create user-friendly self-service portals. Help your users to access the articles and get support 24/7. Upgrade your subscription to enable this feature.",
@@ -1,18 +1,18 @@
{ {
"FILTER": { "FILTER": {
"TITLE": "Филтрирай разговорите", "TITLE": "Филтрирай разговорите",
"SUBTITLE": "Добавете филтри по-долу и натиснете „Прилагане на филтри“, за да филтрирате разговорите.", "SUBTITLE": "Add your filters below and hit 'Apply filters' to cut through the chat clutter.",
"EDIT_CUSTOM_FILTER": "Edit Folder", "EDIT_CUSTOM_FILTER": "Edit Folder",
"CUSTOM_VIEWS_SUBTITLE": "Add or remove filters and update your folder.", "CUSTOM_VIEWS_SUBTITLE": "Add or remove filters and update your folder.",
"ADD_NEW_FILTER": "Добавяне на филтър", "ADD_NEW_FILTER": "Add filter",
"FILTER_DELETE_ERROR": "За да запазите, трябва да имате поне един филтър", "FILTER_DELETE_ERROR": "Oops, looks like we can't save nothing! Please add at least one filter to save it.",
"SUBMIT_BUTTON_LABEL": "Прилагане на филтри", "SUBMIT_BUTTON_LABEL": "Прилагане на филтри",
"UPDATE_BUTTON_LABEL": "Update folder", "UPDATE_BUTTON_LABEL": "Update folder",
"CANCEL_BUTTON_LABEL": "Отмени", "CANCEL_BUTTON_LABEL": "Отмени",
"CLEAR_BUTTON_LABEL": "Изчисти филтрите", "CLEAR_BUTTON_LABEL": "Clear filters",
"EMPTY_VALUE_ERROR": "Изисква се стойност",
"FOLDER_LABEL": "Folder Name", "FOLDER_LABEL": "Folder Name",
"FOLDER_QUERY_LABEL": "Folder Query", "FOLDER_QUERY_LABEL": "Folder Query",
"EMPTY_VALUE_ERROR": "Изисква се стойност.",
"TOOLTIP_LABEL": "Филтрирай разговорите", "TOOLTIP_LABEL": "Филтрирай разговорите",
"QUERY_DROPDOWN_LABELS": { "QUERY_DROPDOWN_LABELS": {
"AND": "И", "AND": "И",
@@ -36,44 +36,44 @@
}, },
"ATTRIBUTES": { "ATTRIBUTES": {
"STATUS": "Статус", "STATUS": "Статус",
"ASSIGNEE_NAME": "Име на правоприемника", "ASSIGNEE_NAME": "Assignee name",
"INBOX_NAME": "Име на входящата кутия", "INBOX_NAME": "Inbox name",
"TEAM_NAME": "Име на екипа", "TEAM_NAME": "Team name",
"CONVERSATION_IDENTIFIER": "Идентивикатор на разговор", "CONVERSATION_IDENTIFIER": "Conversation identifier",
"CAMPAIGN_NAME": "Име на кампания", "CAMPAIGN_NAME": "Campaign name",
"LABELS": "Етикети", "LABELS": "Етикети",
"BROWSER_LANGUAGE": "Език на браузъра", "BROWSER_LANGUAGE": "Browser language",
"PRIORITY": "Priority", "PRIORITY": "Priority",
"COUNTRY_NAME": "Име на държавата", "COUNTRY_NAME": "Country name",
"REFERER_LINK": "Референтна връзка", "REFERER_LINK": "Референтна връзка",
"CUSTOM_ATTRIBUTE_LIST": "List", "CUSTOM_ATTRIBUTE_LIST": "List",
"CUSTOM_ATTRIBUTE_TEXT": "Text", "CUSTOM_ATTRIBUTE_TEXT": "Text",
"CUSTOM_ATTRIBUTE_NUMBER": "Number", "CUSTOM_ATTRIBUTE_NUMBER": "Number",
"CUSTOM_ATTRIBUTE_LINK": "Link", "CUSTOM_ATTRIBUTE_LINK": "Link",
"CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox", "CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox",
"CREATED_AT": "Created At", "CREATED_AT": "Създаден в",
"LAST_ACTIVITY": "Последна активност" "LAST_ACTIVITY": "Last activity"
}, },
"GROUPS": { "GROUPS": {
"STANDARD_FILTERS": "Standard Filters", "STANDARD_FILTERS": "Standard filters",
"ADDITIONAL_FILTERS": "Additional Filters", "ADDITIONAL_FILTERS": "Additional filters",
"CUSTOM_ATTRIBUTES": "Персонализирани атрибути" "CUSTOM_ATTRIBUTES": "Custom attributes"
}, },
"CUSTOM_VIEWS": { "CUSTOM_VIEWS": {
"ADD": { "ADD": {
"TITLE": "Do you want to save this filter?", "TITLE": "Do you want to save this filter?",
"LABEL": "Name this filter", "LABEL": "Name this filter",
"PLACEHOLDER": "Enter a name for this filter", "PLACEHOLDER": "Name your filter to refer it later.",
"ERROR_MESSAGE": "Name is required", "ERROR_MESSAGE": "Name is required.",
"SAVE_BUTTON": "Save filter", "SAVE_BUTTON": "Save filter",
"CANCEL_BUTTON": "Отмени", "CANCEL_BUTTON": "Отмени",
"API_FOLDERS": { "API_FOLDERS": {
"SUCCESS_MESSAGE": "Folder created successfully", "SUCCESS_MESSAGE": "Folder created successfully.",
"ERROR_MESSAGE": "Error while creating folder" "ERROR_MESSAGE": "Error while creating folder."
}, },
"API_SEGMENTS": { "API_SEGMENTS": {
"SUCCESS_MESSAGE": "Segment created successfully", "SUCCESS_MESSAGE": "Segment created successfully.",
"ERROR_MESSAGE": "Error while creating segment" "ERROR_MESSAGE": "Error while creating segment."
} }
}, },
"EDIT": { "EDIT": {
@@ -85,17 +85,17 @@
"CONFIRM": { "CONFIRM": {
"TITLE": "Потвърди изтриването", "TITLE": "Потвърди изтриването",
"MESSAGE": "Are you sure to delete the filter ", "MESSAGE": "Are you sure to delete the filter ",
"YES": "Да, изтрий", "YES": "Yes, delete",
"NO": "No, Keep it" "NO": "No, keep it"
} }
}, },
"API_FOLDERS": { "API_FOLDERS": {
"SUCCESS_MESSAGE": "Folder deleted successfully", "SUCCESS_MESSAGE": "Folder deleted successfully.",
"ERROR_MESSAGE": "Error while deleting folder" "ERROR_MESSAGE": "Error while deleting folder."
}, },
"API_SEGMENTS": { "API_SEGMENTS": {
"SUCCESS_MESSAGE": "Segment deleted successfully", "SUCCESS_MESSAGE": "Segment deleted successfully.",
"ERROR_MESSAGE": "Error while deleting segment" "ERROR_MESSAGE": "Error while deleting segment."
} }
} }
} }
@@ -1,73 +1,73 @@
{ {
"AGENT_BOTS": { "AGENT_BOTS": {
"HEADER": "Bots", "HEADER": "Bots",
"LOADING_EDITOR": "Loading Editor...", "LOADING_EDITOR": "Loading editor...",
"HEADER_BTN_TXT": "Add Bot Configuration", "HEADER_BTN_TXT": "Add bot configuration",
"SIDEBAR_TXT": "<p><b>Agent Bots</b> <p>Agent bots allows you to automate the conversations</p>", "SIDEBAR_TXT": "<p><b>Agent Bots</b> <p>Agent Bots are like the most fabulous members of your team. They can handle the small stuff, so you can focus on the stuff that matters. Give them a try.</p> <p> You can manage your bots from this page or create new ones using the 'Add bot configuraton' button.</p> <p> Open the <a href=\"https://www.chatwoot.com/hc/chatwoot-user-guide-cloud-version/articles/1677497472-how-to-use-agent-bots\" target=\"blank\">Agent bots handbook</a> in another tab for a helping hand.</p>",
"CSML_BOT_EDITOR": { "CSML_BOT_EDITOR": {
"NAME": { "NAME": {
"LABEL": "Bot Name", "LABEL": "Bot name",
"PLACEHOLDER": "Give your bot a name", "PLACEHOLDER": "Name your bot.",
"ERROR": "Bot name is required" "ERROR": "Bot name is required."
}, },
"DESCRIPTION": { "DESCRIPTION": {
"LABEL": "Bot Description", "LABEL": "Bot description",
"PLACEHOLDER": "What does this bot do?" "PLACEHOLDER": "What does this bot do?"
}, },
"BOT_CONFIG": { "BOT_CONFIG": {
"ERROR": "Please enter your CSML bot configuration above", "ERROR": "Please enter your CSML bot configuration above.",
"API_ERROR": "Your CSML configuration is invalid, please fix it and try again." "API_ERROR": "Your CSML configuration is invalid. Please fix it and try again."
}, },
"SUBMIT": "Validate and save" "SUBMIT": "Validate and save"
}, },
"BOT_CONFIGURATION": { "BOT_CONFIGURATION": {
"TITLE": "Select an agent bot", "TITLE": "Select an agent bot",
"DESC": "You can set an agent bot from the list to this inbox. The bot can initially handle the conversation and transfer it to an agent when needed.", "DESC": "Assign an Agent Bot to your inbox. They can handle initial conversations and transfer them to a live agent when necessary.",
"SUBMIT": "Обновяване", "SUBMIT": "Обновяване",
"DISCONNECT": "Disconnect Bot", "DISCONNECT": "Disconnect bot",
"SUCCESS_MESSAGE": "Successfully updated the agent bot", "SUCCESS_MESSAGE": "Successfully updated the agent bot.",
"DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot", "DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot.",
"ERROR_MESSAGE": "Could not update the agent bot, please try again later", "ERROR_MESSAGE": "Could not update the agent bot. Please try again.",
"DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot, please try again later", "DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot. Please try again.",
"SELECT_PLACEHOLDER": "Select Bot" "SELECT_PLACEHOLDER": "Select bot"
}, },
"ADD": { "ADD": {
"TITLE": "Configure new bot", "TITLE": "Configure new bot",
"CANCEL_BUTTON_TEXT": "Отмени", "CANCEL_BUTTON_TEXT": "Отмени",
"API": { "API": {
"SUCCESS_MESSAGE": "Bot added successfully", "SUCCESS_MESSAGE": "Bot added successfully.",
"ERROR_MESSAGE": "Could not add bot, Please try again later" "ERROR_MESSAGE": "Could not add bot. Please try again later."
} }
}, },
"LIST": { "LIST": {
"404": "No Bots found, you can create a bot by clicking the 'Configure new bot' Button ↗", "404": "No bots found. You can create a bot by clicking the 'Configure new bot' button ↗",
"LOADING": "Fetching Bots...", "LOADING": "Fetching bots...",
"TYPE": "Bot Type" "TYPE": "Bot type"
}, },
"DELETE": { "DELETE": {
"BUTTON_TEXT": "Изтрий", "BUTTON_TEXT": "Изтрий",
"TITLE": "Delete Bot", "TITLE": "Delete bot",
"SUBMIT": "Изтрий", "SUBMIT": "Изтрий",
"CANCEL_BUTTON_TEXT": "Отмени", "CANCEL_BUTTON_TEXT": "Отмени",
"DESCRIPTION": "Are you sure you want to delete this bot? This action is irreversible", "DESCRIPTION": "Are you sure you want to delete this bot? This action is irreversible.",
"API": { "API": {
"SUCCESS_MESSAGE": "Bot deleted successfully", "SUCCESS_MESSAGE": "Bot deleted successfully.",
"ERROR_MESSAGE": "Could not able to delete bot, Please try again later" "ERROR_MESSAGE": "Could not delete bot. Please try again."
} }
}, },
"EDIT": { "EDIT": {
"BUTTON_TEXT": "Редактирай", "BUTTON_TEXT": "Редактирай",
"LOADING": "Fetching Bots...", "LOADING": "Fetching bots...",
"TITLE": "Edit Bot", "TITLE": "Edit bot",
"CANCEL_BUTTON_TEXT": "Отмени", "CANCEL_BUTTON_TEXT": "Отмени",
"API": { "API": {
"SUCCESS_MESSAGE": "Bot updated successfully", "SUCCESS_MESSAGE": "Bot updated successfully.",
"ERROR_MESSAGE": "Could not update bot, Please try again later" "ERROR_MESSAGE": "Could not update bot. Please try again."
} }
}, },
"TYPES": { "TYPES": {
"WEBHOOK": "Webhook Bot", "WEBHOOK": "Webhook bot",
"CSML": "CSML Bot" "CSML": "CSML bot"
} }
} }
} }
@@ -1,40 +1,40 @@
{ {
"BULK_ACTION": { "BULK_ACTION": {
"CONVERSATIONS_SELECTED": "%{conversationCount} conversations selected", "CONVERSATIONS_SELECTED": "%{conversationCount} conversations selected",
"AGENT_SELECT_LABEL": "Select Agent", "AGENT_SELECT_LABEL": "Изберете агент",
"ASSIGN_CONFIRMATION_LABEL": "Are you sure to assign %{conversationCount} %{conversationLabel} to", "ASSIGN_CONFIRMATION_LABEL": "Are you sure to assign %{conversationCount} %{conversationLabel} to",
"UNASSIGN_CONFIRMATION_LABEL": "Are you sure to unassign %{conversationCount} %{conversationLabel}?", "UNASSIGN_CONFIRMATION_LABEL": "Are you sure to unassign %{conversationCount} %{conversationLabel}?",
"GO_BACK_LABEL": "Go back", "GO_BACK_LABEL": "Go back",
"ASSIGN_LABEL": "Assign", "ASSIGN_LABEL": "Assign",
"YES": "Yes", "YES": "Yes",
"ASSIGN_AGENT_TOOLTIP": "Assign Agent", "ASSIGN_AGENT_TOOLTIP": "Assign agent",
"ASSIGN_TEAM_TOOLTIP": "Assign team", "ASSIGN_TEAM_TOOLTIP": "Assign team",
"ASSIGN_SUCCESFUL": "Conversations assigned successfully", "ASSIGN_SUCCESFUL": "Conversations assigned successfully.",
"ASSIGN_FAILED": "Failed to assign conversations, please try again", "ASSIGN_FAILED": "Failed to assign conversations. Please try again.",
"RESOLVE_SUCCESFUL": "Conversations resolved successfully", "RESOLVE_SUCCESFUL": "Conversations resolved successfully.",
"RESOLVE_FAILED": "Failed to resolve conversations, please try again", "RESOLVE_FAILED": "Failed to resolve conversations. Please try again.",
"ALL_CONVERSATIONS_SELECTED_ALERT": "Conversations visible on this page are only selected.", "ALL_CONVERSATIONS_SELECTED_ALERT": "Conversations visible on this page are only selected.",
"AGENT_LIST_LOADING": "Loading Agents", "AGENT_LIST_LOADING": "Loading agents",
"UPDATE": { "UPDATE": {
"CHANGE_STATUS": "Change status", "CHANGE_STATUS": "Change status",
"SNOOZE_UNTIL_NEXT_REPLY": "Snooze until next reply", "SNOOZE_UNTIL_NEXT_REPLY": "Snooze until next reply.",
"UPDATE_SUCCESFUL": "Conversation status updated successfully.", "UPDATE_SUCCESFUL": "Conversation status updated successfully.",
"UPDATE_FAILED": "Failed to update conversations, please try again" "UPDATE_FAILED": "Failed to update conversations. Please try again."
}, },
"LABELS": { "LABELS": {
"ASSIGN_LABELS": "Assign Labels", "ASSIGN_LABELS": "Assign labels",
"NO_LABELS_FOUND": "No labels found for", "NO_LABELS_FOUND": "No labels found for",
"ASSIGN_SELECTED_LABELS": "Assign selected labels", "ASSIGN_SELECTED_LABELS": "Assign selected labels",
"ASSIGN_SUCCESFUL": "Labels assigned successfully", "ASSIGN_SUCCESFUL": "Labels assigned successfully.",
"ASSIGN_FAILED": "Failed to assign labels, please try again" "ASSIGN_FAILED": "Failed to assign labels. Please try again."
}, },
"TEAMS": { "TEAMS": {
"TEAM_SELECT_LABEL": "Select Team", "TEAM_SELECT_LABEL": "Изберете екип",
"NONE": "Нито един", "NONE": "Нито един",
"NO_TEAMS_AVAILABLE": "There are no teams added to this account yet.", "NO_TEAMS_AVAILABLE": "There are no teams added to this account yet.",
"ASSIGN_SELECTED_TEAMS": "Assign selected team", "ASSIGN_SELECTED_TEAMS": "Assign selected team.",
"ASSIGN_SUCCESFUL": "Teams assiged successfully", "ASSIGN_SUCCESFUL": "Teams assiged successfully.",
"ASSIGN_FAILED": "Failed to assign team, please try again" "ASSIGN_FAILED": "Failed to assign team. Please try again."
} }
} }
} }
@@ -1,75 +1,75 @@
{ {
"CANNED_MGMT": { "CANNED_MGMT": {
"HEADER": "Готови отговори", "HEADER": "Готови отговори",
"HEADER_BTN_TXT": "Добавяне на готов отговор", "HEADER_BTN_TXT": "Add canned response",
"LOADING": "Извличане на готови отговори", "LOADING": "Fetching canned responses...",
"SEARCH_404": "Няма резултати отговарящи на тази заявка", "SEARCH_404": "Няма резултати отговарящи на тази заявка.",
"SIDEBAR_TXT": "<p><b>Canned Responses</b> </p><p> Canned Responses are saved reply templates which can be used to quickly send out a reply to a conversation. </p><p> For creating a Canned Response, just click on the <b>Add Canned Response</b>. You can also edit or delete an existing Canned Response by clicking on the Edit or Delete button </p><p> Canned responses are used with the help of <b>Short Codes</b>. Agents can access canned responses while on a chat by typing <b>'/'</b> followed by the short code. </p>", "SIDEBAR_TXT": "<p><b>Canned Responses</b> </p><p> Canned Responses are pre-written reply templates that help you quickly respond to a conversation. To insert a canned response during a chat, agents can type a short code preceded by a '/' character. </p><p> You can manage your canned responses from this page or create new ones using the \"Add canned response\" button.</p><p>Open the <a target=\"_blank\" href=\"https://www.chatwoot.com/hc/chatwoot-user-guide-cloud-version/articles/1677501325-how-to-create-saved-reply-templates-with-canned-responses\">Canned Responses handbook</a> in another tab for a helping hand.</p><p>Also, check out the all-new <a href=\"https://www.chatwoot.com/tools/canned-responses-library\" target=\"_blank\">Canned Responses Library</a>.</p>",
"LIST": { "LIST": {
"404": "Няма налични готови отговори в този акаунт.", "404": "Няма налични готови отговори в този акаунт.",
"TITLE": "Управлявайте готовите отговори", "TITLE": "Управлявайте готовите отговори",
"DESC": "Готовите отговори са предварително дефинирани шаблони за отговор, които могат да се изпращат бързо в чата.", "DESC": "Canned Responses are predefined reply templates which can be used to quickly send out replies to conversations.",
"TABLE_HEADER": [ "TABLE_HEADER": [
"Кратък код", "Short code",
"Съдържание", "Съдържание",
"Действия" "Действия"
] ]
}, },
"ADD": { "ADD": {
"TITLE": "Добавяне на готов отговор", "TITLE": "Add canned response",
"DESC": "Canned Responses are saved reply templates which can be used to quickly send out reply to conversation.", "DESC": "Canned Responses are predefined reply templates which can be used to quickly send out replies to conversations.",
"CANCEL_BUTTON_TEXT": "Отмени", "CANCEL_BUTTON_TEXT": "Отмени",
"FORM": { "FORM": {
"SHORT_CODE": { "SHORT_CODE": {
"LABEL": "Кратък код", "LABEL": "Short code",
"PLACEHOLDER": "Please enter a short code", "PLACEHOLDER": "Please enter a short code.",
"ERROR": "Краткия код е задължителен" "ERROR": "Short Code is required."
}, },
"CONTENT": { "CONTENT": {
"LABEL": "Съдържание", "LABEL": "Съобщение",
"PLACEHOLDER": "Моля, въведете съдържание", "PLACEHOLDER": "Please write the message you want to save as a template to use later.",
"ERROR": "Съдържанието е задължително" "ERROR": "Message is required."
}, },
"SUBMIT": "Изпращане" "SUBMIT": "Изпращане"
}, },
"API": { "API": {
"SUCCESS_MESSAGE": "Готовия отговор е добавен успешно", "SUCCESS_MESSAGE": "Canned response added successfully.",
"ERROR_MESSAGE": "Не можа да се свърже с Woot сървър. Моля, опитайте отново по-късно" "ERROR_MESSAGE": "Не можа да се свърже с Woot сървър. Моля, опитайте отново по-късно"
} }
}, },
"EDIT": { "EDIT": {
"TITLE": "Промени готовия отговор", "TITLE": "Edit canned response",
"CANCEL_BUTTON_TEXT": "Отмени", "CANCEL_BUTTON_TEXT": "Отмени",
"FORM": { "FORM": {
"SHORT_CODE": { "SHORT_CODE": {
"LABEL": "Кратък код", "LABEL": "Short code",
"PLACEHOLDER": "Моля, въведете кратък код", "PLACEHOLDER": "Please enter a shortcode.",
"ERROR": "Краткия код е задължителен" "ERROR": "Short code is required."
}, },
"CONTENT": { "CONTENT": {
"LABEL": "Съдържание", "LABEL": "Съобщение",
"PLACEHOLDER": "Моля, въведете съдържание", "PLACEHOLDER": "Please write the message you want to save as a template to use later.",
"ERROR": "Съдържанието е задължително" "ERROR": "Message is required."
}, },
"SUBMIT": "Изпращане" "SUBMIT": "Изпращане"
}, },
"BUTTON_TEXT": "Редактирай", "BUTTON_TEXT": "Редактирай",
"API": { "API": {
"SUCCESS_MESSAGE": "Готовия отговор е обновен успешно", "SUCCESS_MESSAGE": "Canned response is updated successfully.",
"ERROR_MESSAGE": "Не можа да се свърже с Woot сървър. Моля, опитайте отново по-късно" "ERROR_MESSAGE": "Не можа да се свърже с Woot сървър. Моля, опитайте отново по-късно"
} }
}, },
"DELETE": { "DELETE": {
"BUTTON_TEXT": "Изтрий", "BUTTON_TEXT": "Изтрий",
"API": { "API": {
"SUCCESS_MESSAGE": "Готовия отговор е изтрит успешно", "SUCCESS_MESSAGE": "Canned response deleted successfully.",
"ERROR_MESSAGE": "Не можа да се свърже с Woot сървър. Моля, опитайте отново по-късно" "ERROR_MESSAGE": "Не можа да се свърже с Woot сървър. Моля, опитайте отново по-късно"
}, },
"CONFIRM": { "CONFIRM": {
"TITLE": "Потвърди изтриването", "TITLE": "Потвърди изтриването",
"MESSAGE": "Сигурни ли сте за изтриването ", "MESSAGE": "Сигурни ли сте за изтриването ",
"YES": "Да, изтрий ", "YES": "Yes, delete ",
"NO": "Не, запази " "NO": "No, keep "
} }
} }
} }
@@ -51,18 +51,30 @@
"ACTIVE": "Last activity" "ACTIVE": "Last activity"
} }
}, },
"CHAT_SORT_FILTER_ITEMS": { "SORT_ORDER_ITEMS": {
"latest": { "last_activity_at_asc": {
"TEXT": "Last activity" "TEXT": "Last activity: Oldest first"
}, },
"sort_on_created_at": { "last_activity_at_desc": {
"TEXT": "Създаден в" "TEXT": "Last activity: Newest first"
}, },
"sort_on_priority": { "created_at_desc": {
"TEXT": "Priority" "TEXT": "Created at: Newest first"
}, },
"sort_on_waiting_since": { "created_at_asc": {
"TEXT": "Pending Response" "TEXT": "Created at: Oldest first"
},
"priority_desc": {
"TEXT": "Priority: Highest first"
},
"priority_asc": {
"TEXT": "Priority: Lowest first"
},
"waiting_since_asc": {
"TEXT": "Pending Response: Longest first"
},
"waiting_since_desc": {
"TEXT": "Pending Response: Shortest first"
} }
}, },
"ATTACHMENTS": { "ATTACHMENTS": {
@@ -41,6 +41,9 @@
"SAVE_CONTACT": "Save", "SAVE_CONTACT": "Save",
"UPLOADING_ATTACHMENTS": "Uploading attachments...", "UPLOADING_ATTACHMENTS": "Uploading attachments...",
"REPLIED_TO_STORY": "Replied to your story", "REPLIED_TO_STORY": "Replied to your story",
"UNSUPPORTED_MESSAGE": "This message is unsupported.",
"UNSUPPORTED_MESSAGE_FACEBOOK": "This message is unsupported. You can view this message on the Facebook Messenger app.",
"UNSUPPORTED_MESSAGE_INSTAGRAM": "This message is unsupported. You can view this message on the Instagram app.",
"SUCCESS_DELETE_MESSAGE": "Message deleted successfully", "SUCCESS_DELETE_MESSAGE": "Message deleted successfully",
"FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again", "FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again",
"NO_RESPONSE": "No response", "NO_RESPONSE": "No response",
@@ -139,6 +142,7 @@
"PRIVATE_NOTE": "Private Note", "PRIVATE_NOTE": "Private Note",
"SEND": "Send", "SEND": "Send",
"CREATE": "Add Note", "CREATE": "Add Note",
"INSERT_READ_MORE": "Read more",
"DISMISS_REPLY": "Dismiss reply", "DISMISS_REPLY": "Dismiss reply",
"REPLYING_TO": "Replying to:", "REPLYING_TO": "Replying to:",
"TIP_FORMAT_ICON": "Show rich text editor", "TIP_FORMAT_ICON": "Show rich text editor",
@@ -92,7 +92,7 @@
}, },
"NETWORK": { "NETWORK": {
"NOTIFICATION": { "NOTIFICATION": {
"TEXT": "Disconnected from Chatwoot" "OFFLINE": "Offline"
}, },
"BUTTON": { "BUTTON": {
"REFRESH": "Refresh" "REFRESH": "Refresh"
@@ -3,6 +3,7 @@
"HEADER": { "HEADER": {
"FILTER": "Filter by", "FILTER": "Filter by",
"SORT": "Sort by", "SORT": "Sort by",
"LOCALE": "Locale",
"SETTINGS_BUTTON": "Settings", "SETTINGS_BUTTON": "Settings",
"NEW_BUTTON": "New Article", "NEW_BUTTON": "New Article",
"DROPDOWN_OPTIONS": { "DROPDOWN_OPTIONS": {
@@ -15,6 +16,12 @@
"MINE": "My Articles", "MINE": "My Articles",
"DRAFT": "Draft Articles", "DRAFT": "Draft Articles",
"ARCHIVED": "Archived Articles" "ARCHIVED": "Archived Articles"
},
"LOCALE_SELECT": {
"TITLE": "Select locale",
"PLACEHOLDER": "Select locale",
"NO_RESULT": "No locale found",
"SEARCH_PLACEHOLDER": "Search locale"
} }
}, },
"EDIT_HEADER": { "EDIT_HEADER": {
@@ -76,6 +83,9 @@
}, },
"ARTICLE_SEARCH_RESULT": { "ARTICLE_SEARCH_RESULT": {
"UNCATEGORIZED": "Uncategorized", "UNCATEGORIZED": "Uncategorized",
"SEARCH_RESULTS": "Search results for %{query}",
"EMPTY_TEXT": "Search for articles to insert into replies.",
"SEARCH_LOADER": "Searching...",
"INSERT_ARTICLE": "Insert", "INSERT_ARTICLE": "Insert",
"NO_RESULT": "No articles found", "NO_RESULT": "No articles found",
"COPY_LINK": "Copy article link to clipboard", "COPY_LINK": "Copy article link to clipboard",
@@ -220,7 +230,10 @@
"LOGO": { "LOGO": {
"LABEL": "Logo", "LABEL": "Logo",
"UPLOAD_BUTTON": "Upload logo", "UPLOAD_BUTTON": "Upload logo",
"HELP_TEXT": "This logo will be displayed on the portal header." "HELP_TEXT": "This logo will be displayed on the portal header.",
"IMAGE_UPLOAD_SUCCESS": "Logo uploaded successfully",
"IMAGE_UPLOAD_ERROR": "Logo deleted successfully",
"IMAGE_DELETE_ERROR": "Error while deleting logo"
}, },
"NAME": { "NAME": {
"LABEL": "Име", "LABEL": "Име",
@@ -426,6 +439,21 @@
} }
} }
}, },
"ARTICLE_SEARCH": {
"TITLE": "Search articles",
"PLACEHOLDER": "Search articles",
"NO_RESULT": "No articles found",
"SEARCHING": "Searching...",
"SEARCH_BUTTON": "Търсене",
"INSERT_ARTICLE": "Insert link",
"IFRAME_ERROR": "URL is empty or invalid. Unable to display content.",
"OPEN_ARTICLE_SEARCH": "Insert article from Help Center",
"SUCCESS_ARTICLE_INSERTED": "Article inserted successfully",
"PREVIEW_LINK": "Preview article",
"CANCEL": "Затвори",
"BACK": "Back",
"BACK_RESULTS": "Back to results"
},
"UPGRADE_PAGE": { "UPGRADE_PAGE": {
"TITLE": "Help Center", "TITLE": "Help Center",
"DESCRIPTION": "Create user-friendly self-service portals. Help your users to access the articles and get support 24/7. Upgrade your subscription to enable this feature.", "DESCRIPTION": "Create user-friendly self-service portals. Help your users to access the articles and get support 24/7. Upgrade your subscription to enable this feature.",
@@ -1,18 +1,18 @@
{ {
"FILTER": { "FILTER": {
"TITLE": "Filtre de converses", "TITLE": "Filtre de converses",
"SUBTITLE": "Add filters below and hit 'Apply filters' to filter conversations.", "SUBTITLE": "Add your filters below and hit 'Apply filters' to cut through the chat clutter.",
"EDIT_CUSTOM_FILTER": "Edit Folder", "EDIT_CUSTOM_FILTER": "Edit Folder",
"CUSTOM_VIEWS_SUBTITLE": "Add or remove filters and update your folder.", "CUSTOM_VIEWS_SUBTITLE": "Add or remove filters and update your folder.",
"ADD_NEW_FILTER": "Afegeix filtre", "ADD_NEW_FILTER": "Add filter",
"FILTER_DELETE_ERROR": "You should have atleast one filter to save", "FILTER_DELETE_ERROR": "Oops, looks like we can't save nothing! Please add at least one filter to save it.",
"SUBMIT_BUTTON_LABEL": "Aplicar filtres", "SUBMIT_BUTTON_LABEL": "Aplicar filtres",
"UPDATE_BUTTON_LABEL": "Update folder", "UPDATE_BUTTON_LABEL": "Update folder",
"CANCEL_BUTTON_LABEL": "Cancel·la", "CANCEL_BUTTON_LABEL": "Cancel·la",
"CLEAR_BUTTON_LABEL": "Clear Filters", "CLEAR_BUTTON_LABEL": "Clear filters",
"EMPTY_VALUE_ERROR": "El valor és necessari",
"FOLDER_LABEL": "Folder Name", "FOLDER_LABEL": "Folder Name",
"FOLDER_QUERY_LABEL": "Folder Query", "FOLDER_QUERY_LABEL": "Folder Query",
"EMPTY_VALUE_ERROR": "El valor és necessari.",
"TOOLTIP_LABEL": "Filtre de converses", "TOOLTIP_LABEL": "Filtre de converses",
"QUERY_DROPDOWN_LABELS": { "QUERY_DROPDOWN_LABELS": {
"AND": "I", "AND": "I",
@@ -36,44 +36,44 @@
}, },
"ATTRIBUTES": { "ATTRIBUTES": {
"STATUS": "Estat", "STATUS": "Estat",
"ASSIGNEE_NAME": "Assignee Name", "ASSIGNEE_NAME": "Assignee name",
"INBOX_NAME": "Nom de la safata d'entrada", "INBOX_NAME": "Inbox name",
"TEAM_NAME": "Nom de l'equip", "TEAM_NAME": "Team name",
"CONVERSATION_IDENTIFIER": "Identificador de la conversa", "CONVERSATION_IDENTIFIER": "Conversation identifier",
"CAMPAIGN_NAME": "Campaign Name", "CAMPAIGN_NAME": "Campaign name",
"LABELS": "Etiquetes", "LABELS": "Etiquetes",
"BROWSER_LANGUAGE": "Browser Language", "BROWSER_LANGUAGE": "Browser language",
"PRIORITY": "Priority", "PRIORITY": "Priority",
"COUNTRY_NAME": "Nom del país", "COUNTRY_NAME": "Country name",
"REFERER_LINK": "Referer link", "REFERER_LINK": "Referer link",
"CUSTOM_ATTRIBUTE_LIST": "List", "CUSTOM_ATTRIBUTE_LIST": "List",
"CUSTOM_ATTRIBUTE_TEXT": "Llista", "CUSTOM_ATTRIBUTE_TEXT": "Llista",
"CUSTOM_ATTRIBUTE_NUMBER": "Número", "CUSTOM_ATTRIBUTE_NUMBER": "Número",
"CUSTOM_ATTRIBUTE_LINK": "Enllaç", "CUSTOM_ATTRIBUTE_LINK": "Enllaç",
"CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox", "CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox",
"CREATED_AT": "Created At", "CREATED_AT": "Created at",
"LAST_ACTIVITY": "Last Activity" "LAST_ACTIVITY": "Last activity"
}, },
"GROUPS": { "GROUPS": {
"STANDARD_FILTERS": "Standard Filters", "STANDARD_FILTERS": "Standard filters",
"ADDITIONAL_FILTERS": "Additional Filters", "ADDITIONAL_FILTERS": "Additional filters",
"CUSTOM_ATTRIBUTES": "Atributs personalitzats" "CUSTOM_ATTRIBUTES": "Custom attributes"
}, },
"CUSTOM_VIEWS": { "CUSTOM_VIEWS": {
"ADD": { "ADD": {
"TITLE": "Do you want to save this filter?", "TITLE": "Do you want to save this filter?",
"LABEL": "Name this filter", "LABEL": "Name this filter",
"PLACEHOLDER": "Enter a name for this filter", "PLACEHOLDER": "Name your filter to refer it later.",
"ERROR_MESSAGE": "Name is required", "ERROR_MESSAGE": "Name is required.",
"SAVE_BUTTON": "Save filter", "SAVE_BUTTON": "Save filter",
"CANCEL_BUTTON": "Cancel·la", "CANCEL_BUTTON": "Cancel·la",
"API_FOLDERS": { "API_FOLDERS": {
"SUCCESS_MESSAGE": "Folder created successfully", "SUCCESS_MESSAGE": "Folder created successfully.",
"ERROR_MESSAGE": "Error while creating folder" "ERROR_MESSAGE": "Error while creating folder."
}, },
"API_SEGMENTS": { "API_SEGMENTS": {
"SUCCESS_MESSAGE": "Segment created successfully", "SUCCESS_MESSAGE": "Segment created successfully.",
"ERROR_MESSAGE": "Error while creating segment" "ERROR_MESSAGE": "Error while creating segment."
} }
}, },
"EDIT": { "EDIT": {
@@ -83,19 +83,19 @@
"DELETE_BUTTON": "Delete filter", "DELETE_BUTTON": "Delete filter",
"MODAL": { "MODAL": {
"CONFIRM": { "CONFIRM": {
"TITLE": "Confirma l'esborrat", "TITLE": "Confirm deletion",
"MESSAGE": "Are you sure to delete the filter ", "MESSAGE": "Are you sure to delete the filter ",
"YES": "Si, esborra", "YES": "Yes, delete",
"NO": "No, manten-la" "NO": "No, keep it"
} }
}, },
"API_FOLDERS": { "API_FOLDERS": {
"SUCCESS_MESSAGE": "Folder deleted successfully", "SUCCESS_MESSAGE": "Folder deleted successfully.",
"ERROR_MESSAGE": "Error while deleting folder" "ERROR_MESSAGE": "Error while deleting folder."
}, },
"API_SEGMENTS": { "API_SEGMENTS": {
"SUCCESS_MESSAGE": "Segment deleted successfully", "SUCCESS_MESSAGE": "Segment deleted successfully.",
"ERROR_MESSAGE": "Error while deleting segment" "ERROR_MESSAGE": "Error while deleting segment."
} }
} }
} }
@@ -1,73 +1,73 @@
{ {
"AGENT_BOTS": { "AGENT_BOTS": {
"HEADER": "Bots", "HEADER": "Bots",
"LOADING_EDITOR": "Loading Editor...", "LOADING_EDITOR": "Loading editor...",
"HEADER_BTN_TXT": "Add Bot Configuration", "HEADER_BTN_TXT": "Add bot configuration",
"SIDEBAR_TXT": "<p><b>Agent Bots</b> <p>Agent bots allows you to automate the conversations</p>", "SIDEBAR_TXT": "<p><b>Agent Bots</b> <p>Agent Bots are like the most fabulous members of your team. They can handle the small stuff, so you can focus on the stuff that matters. Give them a try.</p> <p> You can manage your bots from this page or create new ones using the 'Add bot configuraton' button.</p> <p> Open the <a href=\"https://www.chatwoot.com/hc/chatwoot-user-guide-cloud-version/articles/1677497472-how-to-use-agent-bots\" target=\"blank\">Agent bots handbook</a> in another tab for a helping hand.</p>",
"CSML_BOT_EDITOR": { "CSML_BOT_EDITOR": {
"NAME": { "NAME": {
"LABEL": "Bot Name", "LABEL": "Bot name",
"PLACEHOLDER": "Give your bot a name", "PLACEHOLDER": "Name your bot.",
"ERROR": "Bot name is required" "ERROR": "Bot name is required."
}, },
"DESCRIPTION": { "DESCRIPTION": {
"LABEL": "Bot Description", "LABEL": "Bot description",
"PLACEHOLDER": "What does this bot do?" "PLACEHOLDER": "What does this bot do?"
}, },
"BOT_CONFIG": { "BOT_CONFIG": {
"ERROR": "Please enter your CSML bot configuration above", "ERROR": "Please enter your CSML bot configuration above.",
"API_ERROR": "Your CSML configuration is invalid, please fix it and try again." "API_ERROR": "Your CSML configuration is invalid. Please fix it and try again."
}, },
"SUBMIT": "Validate and save" "SUBMIT": "Validate and save"
}, },
"BOT_CONFIGURATION": { "BOT_CONFIGURATION": {
"TITLE": "Select an agent bot", "TITLE": "Select an agent bot",
"DESC": "You can set an agent bot from the list to this inbox. The bot can initially handle the conversation and transfer it to an agent when needed.", "DESC": "Assign an Agent Bot to your inbox. They can handle initial conversations and transfer them to a live agent when necessary.",
"SUBMIT": "Actualitza", "SUBMIT": "Actualitza",
"DISCONNECT": "Disconnect Bot", "DISCONNECT": "Disconnect bot",
"SUCCESS_MESSAGE": "Successfully updated the agent bot", "SUCCESS_MESSAGE": "Successfully updated the agent bot.",
"DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot", "DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot.",
"ERROR_MESSAGE": "Could not update the agent bot, please try again later", "ERROR_MESSAGE": "Could not update the agent bot. Please try again.",
"DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot, please try again later", "DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot. Please try again.",
"SELECT_PLACEHOLDER": "Select Bot" "SELECT_PLACEHOLDER": "Select bot"
}, },
"ADD": { "ADD": {
"TITLE": "Configure new bot", "TITLE": "Configure new bot",
"CANCEL_BUTTON_TEXT": "Cancel·la", "CANCEL_BUTTON_TEXT": "Cancel·la",
"API": { "API": {
"SUCCESS_MESSAGE": "Bot added successfully", "SUCCESS_MESSAGE": "Bot added successfully.",
"ERROR_MESSAGE": "Could not add bot, Please try again later" "ERROR_MESSAGE": "Could not add bot. Please try again later."
} }
}, },
"LIST": { "LIST": {
"404": "No Bots found, you can create a bot by clicking the 'Configure new bot' Button ↗", "404": "No bots found. You can create a bot by clicking the 'Configure new bot' button ↗",
"LOADING": "Fetching Bots...", "LOADING": "Fetching bots...",
"TYPE": "Bot Type" "TYPE": "Bot type"
}, },
"DELETE": { "DELETE": {
"BUTTON_TEXT": "Esborrar", "BUTTON_TEXT": "Esborrar",
"TITLE": "Delete Bot", "TITLE": "Delete bot",
"SUBMIT": "Esborrar", "SUBMIT": "Esborrar",
"CANCEL_BUTTON_TEXT": "Cancel·la", "CANCEL_BUTTON_TEXT": "Cancel·la",
"DESCRIPTION": "Are you sure you want to delete this bot? This action is irreversible", "DESCRIPTION": "Are you sure you want to delete this bot? This action is irreversible.",
"API": { "API": {
"SUCCESS_MESSAGE": "Bot deleted successfully", "SUCCESS_MESSAGE": "Bot deleted successfully.",
"ERROR_MESSAGE": "Could not able to delete bot, Please try again later" "ERROR_MESSAGE": "Could not delete bot. Please try again."
} }
}, },
"EDIT": { "EDIT": {
"BUTTON_TEXT": "Edita", "BUTTON_TEXT": "Edita",
"LOADING": "Fetching Bots...", "LOADING": "Fetching bots...",
"TITLE": "Edit Bot", "TITLE": "Edit bot",
"CANCEL_BUTTON_TEXT": "Cancel·la", "CANCEL_BUTTON_TEXT": "Cancel·la",
"API": { "API": {
"SUCCESS_MESSAGE": "Bot updated successfully", "SUCCESS_MESSAGE": "Bot updated successfully.",
"ERROR_MESSAGE": "Could not update bot, Please try again later" "ERROR_MESSAGE": "Could not update bot. Please try again."
} }
}, },
"TYPES": { "TYPES": {
"WEBHOOK": "Webhook Bot", "WEBHOOK": "Webhook bot",
"CSML": "CSML Bot" "CSML": "CSML bot"
} }
} }
} }
@@ -7,34 +7,34 @@
"GO_BACK_LABEL": "Go back", "GO_BACK_LABEL": "Go back",
"ASSIGN_LABEL": "Assignar", "ASSIGN_LABEL": "Assignar",
"YES": "Si", "YES": "Si",
"ASSIGN_AGENT_TOOLTIP": "Assign Agent", "ASSIGN_AGENT_TOOLTIP": "Assign agent",
"ASSIGN_TEAM_TOOLTIP": "Assign team", "ASSIGN_TEAM_TOOLTIP": "Assign team",
"ASSIGN_SUCCESFUL": "Conversations assigned successfully", "ASSIGN_SUCCESFUL": "Conversations assigned successfully.",
"ASSIGN_FAILED": "Failed to assign conversations, please try again", "ASSIGN_FAILED": "Failed to assign conversations. Please try again.",
"RESOLVE_SUCCESFUL": "Conversations resolved successfully", "RESOLVE_SUCCESFUL": "Conversations resolved successfully.",
"RESOLVE_FAILED": "Failed to resolve conversations, please try again", "RESOLVE_FAILED": "Failed to resolve conversations. Please try again.",
"ALL_CONVERSATIONS_SELECTED_ALERT": "Conversations visible on this page are only selected.", "ALL_CONVERSATIONS_SELECTED_ALERT": "Conversations visible on this page are only selected.",
"AGENT_LIST_LOADING": "Loading Agents", "AGENT_LIST_LOADING": "Loading agents",
"UPDATE": { "UPDATE": {
"CHANGE_STATUS": "Change status", "CHANGE_STATUS": "Change status",
"SNOOZE_UNTIL_NEXT_REPLY": "Snooze until next reply", "SNOOZE_UNTIL_NEXT_REPLY": "Snooze until next reply.",
"UPDATE_SUCCESFUL": "Conversation status updated successfully.", "UPDATE_SUCCESFUL": "Conversation status updated successfully.",
"UPDATE_FAILED": "Failed to update conversations, please try again" "UPDATE_FAILED": "Failed to update conversations. Please try again."
}, },
"LABELS": { "LABELS": {
"ASSIGN_LABELS": "Assign Labels", "ASSIGN_LABELS": "Assign labels",
"NO_LABELS_FOUND": "No labels found for", "NO_LABELS_FOUND": "No labels found for",
"ASSIGN_SELECTED_LABELS": "Assign selected labels", "ASSIGN_SELECTED_LABELS": "Assign selected labels",
"ASSIGN_SUCCESFUL": "Labels assigned successfully", "ASSIGN_SUCCESFUL": "Labels assigned successfully.",
"ASSIGN_FAILED": "Failed to assign labels, please try again" "ASSIGN_FAILED": "Failed to assign labels. Please try again."
}, },
"TEAMS": { "TEAMS": {
"TEAM_SELECT_LABEL": "Select Team", "TEAM_SELECT_LABEL": "Selecciona equip",
"NONE": "Ningú", "NONE": "Ningú",
"NO_TEAMS_AVAILABLE": "There are no teams added to this account yet.", "NO_TEAMS_AVAILABLE": "There are no teams added to this account yet.",
"ASSIGN_SELECTED_TEAMS": "Assign selected team", "ASSIGN_SELECTED_TEAMS": "Assign selected team.",
"ASSIGN_SUCCESFUL": "Teams assiged successfully", "ASSIGN_SUCCESFUL": "Teams assiged successfully.",
"ASSIGN_FAILED": "Failed to assign team, please try again" "ASSIGN_FAILED": "Failed to assign team. Please try again."
} }
} }
} }
@@ -1,75 +1,75 @@
{ {
"CANNED_MGMT": { "CANNED_MGMT": {
"HEADER": "Respostes predeterminades", "HEADER": "Respostes predeterminades",
"HEADER_BTN_TXT": "Afegeix una resposta predeterminada", "HEADER_BTN_TXT": "Add canned response",
"LOADING": "S'estan recollint les respostes predeterminades", "LOADING": "Fetching canned responses...",
"SEARCH_404": "No hi ha cap resposta que coincideixi amb aquesta consulta", "SEARCH_404": "No hi ha cap resposta que coincideixi amb aquesta consulta.",
"SIDEBAR_TXT": "<p><b>Canned Responses</b> </p><p> Canned Responses are saved reply templates which can be used to quickly send out a reply to a conversation. </p><p> For creating a Canned Response, just click on the <b>Add Canned Response</b>. You can also edit or delete an existing Canned Response by clicking on the Edit or Delete button </p><p> Canned responses are used with the help of <b>Short Codes</b>. Agents can access canned responses while on a chat by typing <b>'/'</b> followed by the short code. </p>", "SIDEBAR_TXT": "<p><b>Canned Responses</b> </p><p> Canned Responses are pre-written reply templates that help you quickly respond to a conversation. To insert a canned response during a chat, agents can type a short code preceded by a '/' character. </p><p> You can manage your canned responses from this page or create new ones using the \"Add canned response\" button.</p><p>Open the <a target=\"_blank\" href=\"https://www.chatwoot.com/hc/chatwoot-user-guide-cloud-version/articles/1677501325-how-to-create-saved-reply-templates-with-canned-responses\">Canned Responses handbook</a> in another tab for a helping hand.</p><p>Also, check out the all-new <a href=\"https://www.chatwoot.com/tools/canned-responses-library\" target=\"_blank\">Canned Responses Library</a>.</p>",
"LIST": { "LIST": {
"404": "No hi ha respostes predeterminades disponibles en aquest compte.", "404": "No hi ha respostes predeterminades disponibles en aquest compte.",
"TITLE": "Gestiona les respostes predeterminades", "TITLE": "Gestiona les respostes predeterminades",
"DESC": "Les respostes predeterminades són plantilles de resposta predefinides que es poden utilitzar per enviar ràpidament respostes a les converses.", "DESC": "Canned Responses are predefined reply templates which can be used to quickly send out replies to conversations.",
"TABLE_HEADER": [ "TABLE_HEADER": [
"Codi curt", "Short code",
"Contingut", "Contingut",
"Accions" "Accions"
] ]
}, },
"ADD": { "ADD": {
"TITLE": "Afegeix Resposta Predeterminada", "TITLE": "Add canned response",
"DESC": "Canned Responses are saved reply templates which can be used to quickly send out reply to conversation.", "DESC": "Canned Responses are predefined reply templates which can be used to quickly send out replies to conversations.",
"CANCEL_BUTTON_TEXT": "Cancel·la", "CANCEL_BUTTON_TEXT": "Cancel·la",
"FORM": { "FORM": {
"SHORT_CODE": { "SHORT_CODE": {
"LABEL": "Codi curt", "LABEL": "Short code",
"PLACEHOLDER": "Introduïu un codi curt", "PLACEHOLDER": "Please enter a short code.",
"ERROR": "És necessari el codi curt" "ERROR": "Short Code is required."
}, },
"CONTENT": { "CONTENT": {
"LABEL": "Contingut", "LABEL": "Missatge",
"PLACEHOLDER": "Introduïu un contingut", "PLACEHOLDER": "Please write the message you want to save as a template to use later.",
"ERROR": "És necessari un contingut" "ERROR": "Message is required."
}, },
"SUBMIT": "Envia" "SUBMIT": "Envia"
}, },
"API": { "API": {
"SUCCESS_MESSAGE": "Resposta predeterminada afegida correctament", "SUCCESS_MESSAGE": "Canned response added successfully.",
"ERROR_MESSAGE": "No s'ha pogut connectar amb el servidor Woot. Torna-ho a provar més endavant" "ERROR_MESSAGE": "No s'ha pogut connectar amb el servidor Woot. Torna-ho a provar més endavant"
} }
}, },
"EDIT": { "EDIT": {
"TITLE": "Edita la resposta predeterminada", "TITLE": "Edit canned response",
"CANCEL_BUTTON_TEXT": "Cancel·la", "CANCEL_BUTTON_TEXT": "Cancel·la",
"FORM": { "FORM": {
"SHORT_CODE": { "SHORT_CODE": {
"LABEL": "Codi curt", "LABEL": "Short code",
"PLACEHOLDER": "Introduïu un codi curt", "PLACEHOLDER": "Please enter a shortcode.",
"ERROR": "És necessari el codi curt" "ERROR": "Short code is required."
}, },
"CONTENT": { "CONTENT": {
"LABEL": "Contingut", "LABEL": "Missatge",
"PLACEHOLDER": "Introduïu un contingut", "PLACEHOLDER": "Please write the message you want to save as a template to use later.",
"ERROR": "És necessari un contingut" "ERROR": "Message is required."
}, },
"SUBMIT": "Envia" "SUBMIT": "Envia"
}, },
"BUTTON_TEXT": "Edita", "BUTTON_TEXT": "Edita",
"API": { "API": {
"SUCCESS_MESSAGE": "Resposta predeterminada actualitzada correctament", "SUCCESS_MESSAGE": "Canned response is updated successfully.",
"ERROR_MESSAGE": "No s'ha pogut connectar amb el servidor Woot. Torna-ho a provar més endavant" "ERROR_MESSAGE": "No s'ha pogut connectar amb el servidor Woot. Torna-ho a provar més endavant"
} }
}, },
"DELETE": { "DELETE": {
"BUTTON_TEXT": "Esborra", "BUTTON_TEXT": "Esborra",
"API": { "API": {
"SUCCESS_MESSAGE": "Resposta predeterminada eliminada correctament", "SUCCESS_MESSAGE": "Canned response deleted successfully.",
"ERROR_MESSAGE": "No s'ha pogut connectar amb el servidor Woot. Torna-ho a provar més endavant" "ERROR_MESSAGE": "No s'ha pogut connectar amb el servidor Woot. Torna-ho a provar més endavant"
}, },
"CONFIRM": { "CONFIRM": {
"TITLE": "Confirma esborrat", "TITLE": "Confirm deletion",
"MESSAGE": "N'estas segur ", "MESSAGE": "N'estas segur ",
"YES": "Si, esborra ", "YES": "Yes, delete ",
"NO": "No, segueix " "NO": "No, keep "
} }
} }
} }
@@ -51,18 +51,30 @@
"ACTIVE": "Last activity" "ACTIVE": "Last activity"
} }
}, },
"CHAT_SORT_FILTER_ITEMS": { "SORT_ORDER_ITEMS": {
"latest": { "last_activity_at_asc": {
"TEXT": "Last activity" "TEXT": "Last activity: Oldest first"
}, },
"sort_on_created_at": { "last_activity_at_desc": {
"TEXT": "Created at" "TEXT": "Last activity: Newest first"
}, },
"sort_on_priority": { "created_at_desc": {
"TEXT": "Priority" "TEXT": "Created at: Newest first"
}, },
"sort_on_waiting_since": { "created_at_asc": {
"TEXT": "Pending Response" "TEXT": "Created at: Oldest first"
},
"priority_desc": {
"TEXT": "Priority: Highest first"
},
"priority_asc": {
"TEXT": "Priority: Lowest first"
},
"waiting_since_asc": {
"TEXT": "Pending Response: Longest first"
},
"waiting_since_desc": {
"TEXT": "Pending Response: Shortest first"
} }
}, },
"ATTACHMENTS": { "ATTACHMENTS": {
@@ -41,6 +41,9 @@
"SAVE_CONTACT": "Save", "SAVE_CONTACT": "Save",
"UPLOADING_ATTACHMENTS": "Pujant fitxers adjunts...", "UPLOADING_ATTACHMENTS": "Pujant fitxers adjunts...",
"REPLIED_TO_STORY": "Replied to your story", "REPLIED_TO_STORY": "Replied to your story",
"UNSUPPORTED_MESSAGE": "This message is unsupported.",
"UNSUPPORTED_MESSAGE_FACEBOOK": "This message is unsupported. You can view this message on the Facebook Messenger app.",
"UNSUPPORTED_MESSAGE_INSTAGRAM": "This message is unsupported. You can view this message on the Instagram app.",
"SUCCESS_DELETE_MESSAGE": "Message deleted successfully", "SUCCESS_DELETE_MESSAGE": "Message deleted successfully",
"FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again", "FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again",
"NO_RESPONSE": "Sense resposta", "NO_RESPONSE": "Sense resposta",
@@ -139,6 +142,7 @@
"PRIVATE_NOTE": "Nota privada", "PRIVATE_NOTE": "Nota privada",
"SEND": "Envia", "SEND": "Envia",
"CREATE": "Afegeix una nota", "CREATE": "Afegeix una nota",
"INSERT_READ_MORE": "Read more",
"DISMISS_REPLY": "Dismiss reply", "DISMISS_REPLY": "Dismiss reply",
"REPLYING_TO": "Replying to:", "REPLYING_TO": "Replying to:",
"TIP_FORMAT_ICON": "Mostra l'editor de text enriquit", "TIP_FORMAT_ICON": "Mostra l'editor de text enriquit",
@@ -92,7 +92,7 @@
}, },
"NETWORK": { "NETWORK": {
"NOTIFICATION": { "NOTIFICATION": {
"TEXT": "Disconnected from Chatwoot" "OFFLINE": "Fora de línia"
}, },
"BUTTON": { "BUTTON": {
"REFRESH": "Refresh" "REFRESH": "Refresh"
@@ -3,6 +3,7 @@
"HEADER": { "HEADER": {
"FILTER": "Filter by", "FILTER": "Filter by",
"SORT": "Sort by", "SORT": "Sort by",
"LOCALE": "Locale",
"SETTINGS_BUTTON": "Configuracions", "SETTINGS_BUTTON": "Configuracions",
"NEW_BUTTON": "New Article", "NEW_BUTTON": "New Article",
"DROPDOWN_OPTIONS": { "DROPDOWN_OPTIONS": {
@@ -15,6 +16,12 @@
"MINE": "My Articles", "MINE": "My Articles",
"DRAFT": "Draft Articles", "DRAFT": "Draft Articles",
"ARCHIVED": "Archived Articles" "ARCHIVED": "Archived Articles"
},
"LOCALE_SELECT": {
"TITLE": "Select locale",
"PLACEHOLDER": "Select locale",
"NO_RESULT": "No locale found",
"SEARCH_PLACEHOLDER": "Search locale"
} }
}, },
"EDIT_HEADER": { "EDIT_HEADER": {
@@ -76,6 +83,9 @@
}, },
"ARTICLE_SEARCH_RESULT": { "ARTICLE_SEARCH_RESULT": {
"UNCATEGORIZED": "Uncategorized", "UNCATEGORIZED": "Uncategorized",
"SEARCH_RESULTS": "Search results for %{query}",
"EMPTY_TEXT": "Search for articles to insert into replies.",
"SEARCH_LOADER": "Searching...",
"INSERT_ARTICLE": "Insert", "INSERT_ARTICLE": "Insert",
"NO_RESULT": "No articles found", "NO_RESULT": "No articles found",
"COPY_LINK": "Copy article link to clipboard", "COPY_LINK": "Copy article link to clipboard",
@@ -220,7 +230,10 @@
"LOGO": { "LOGO": {
"LABEL": "Logo", "LABEL": "Logo",
"UPLOAD_BUTTON": "Upload logo", "UPLOAD_BUTTON": "Upload logo",
"HELP_TEXT": "This logo will be displayed on the portal header." "HELP_TEXT": "This logo will be displayed on the portal header.",
"IMAGE_UPLOAD_SUCCESS": "Logo uploaded successfully",
"IMAGE_UPLOAD_ERROR": "Logo deleted successfully",
"IMAGE_DELETE_ERROR": "Error while deleting logo"
}, },
"NAME": { "NAME": {
"LABEL": "Nom", "LABEL": "Nom",
@@ -426,6 +439,21 @@
} }
} }
}, },
"ARTICLE_SEARCH": {
"TITLE": "Search articles",
"PLACEHOLDER": "Search articles",
"NO_RESULT": "No articles found",
"SEARCHING": "Searching...",
"SEARCH_BUTTON": "Cercar",
"INSERT_ARTICLE": "Insert link",
"IFRAME_ERROR": "URL is empty or invalid. Unable to display content.",
"OPEN_ARTICLE_SEARCH": "Insert article from Help Center",
"SUCCESS_ARTICLE_INSERTED": "Article inserted successfully",
"PREVIEW_LINK": "Preview article",
"CANCEL": "Tanca",
"BACK": "Enrere",
"BACK_RESULTS": "Back to results"
},
"UPGRADE_PAGE": { "UPGRADE_PAGE": {
"TITLE": "Help Center", "TITLE": "Help Center",
"DESCRIPTION": "Create user-friendly self-service portals. Help your users to access the articles and get support 24/7. Upgrade your subscription to enable this feature.", "DESCRIPTION": "Create user-friendly self-service portals. Help your users to access the articles and get support 24/7. Upgrade your subscription to enable this feature.",
@@ -1,18 +1,18 @@
{ {
"FILTER": { "FILTER": {
"TITLE": "Filter Conversations", "TITLE": "Filter conversations",
"SUBTITLE": "Add filters below and hit 'Apply filters' to filter conversations.", "SUBTITLE": "Add your filters below and hit 'Apply filters' to cut through the chat clutter.",
"EDIT_CUSTOM_FILTER": "Edit Folder", "EDIT_CUSTOM_FILTER": "Edit Folder",
"CUSTOM_VIEWS_SUBTITLE": "Add or remove filters and update your folder.", "CUSTOM_VIEWS_SUBTITLE": "Add or remove filters and update your folder.",
"ADD_NEW_FILTER": "Add Filter", "ADD_NEW_FILTER": "Add filter",
"FILTER_DELETE_ERROR": "You should have atleast one filter to save", "FILTER_DELETE_ERROR": "Oops, looks like we can't save nothing! Please add at least one filter to save it.",
"SUBMIT_BUTTON_LABEL": "Apply filters", "SUBMIT_BUTTON_LABEL": "Apply filters",
"UPDATE_BUTTON_LABEL": "Update folder", "UPDATE_BUTTON_LABEL": "Update folder",
"CANCEL_BUTTON_LABEL": "Zrušit", "CANCEL_BUTTON_LABEL": "Zrušit",
"CLEAR_BUTTON_LABEL": "Clear Filters", "CLEAR_BUTTON_LABEL": "Clear filters",
"EMPTY_VALUE_ERROR": "Value is required",
"FOLDER_LABEL": "Folder Name", "FOLDER_LABEL": "Folder Name",
"FOLDER_QUERY_LABEL": "Folder Query", "FOLDER_QUERY_LABEL": "Folder Query",
"EMPTY_VALUE_ERROR": "Hodnota je povinná.",
"TOOLTIP_LABEL": "Filter conversations", "TOOLTIP_LABEL": "Filter conversations",
"QUERY_DROPDOWN_LABELS": { "QUERY_DROPDOWN_LABELS": {
"AND": "AND", "AND": "AND",
@@ -36,44 +36,44 @@
}, },
"ATTRIBUTES": { "ATTRIBUTES": {
"STATUS": "Stav", "STATUS": "Stav",
"ASSIGNEE_NAME": "Assignee Name", "ASSIGNEE_NAME": "Assignee name",
"INBOX_NAME": "Název schránky", "INBOX_NAME": "Inbox name",
"TEAM_NAME": "Team Name", "TEAM_NAME": "Team name",
"CONVERSATION_IDENTIFIER": "Conversation Identifier", "CONVERSATION_IDENTIFIER": "Conversation identifier",
"CAMPAIGN_NAME": "Campaign Name", "CAMPAIGN_NAME": "Campaign name",
"LABELS": "Štítky", "LABELS": "Štítky",
"BROWSER_LANGUAGE": "Browser Language", "BROWSER_LANGUAGE": "Browser language",
"PRIORITY": "Priority", "PRIORITY": "Priority",
"COUNTRY_NAME": "Country Name", "COUNTRY_NAME": "Country name",
"REFERER_LINK": "Referer link", "REFERER_LINK": "Referer link",
"CUSTOM_ATTRIBUTE_LIST": "List", "CUSTOM_ATTRIBUTE_LIST": "List",
"CUSTOM_ATTRIBUTE_TEXT": "Text", "CUSTOM_ATTRIBUTE_TEXT": "Text",
"CUSTOM_ATTRIBUTE_NUMBER": "Number", "CUSTOM_ATTRIBUTE_NUMBER": "Number",
"CUSTOM_ATTRIBUTE_LINK": "Link", "CUSTOM_ATTRIBUTE_LINK": "Link",
"CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox", "CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox",
"CREATED_AT": "Created At", "CREATED_AT": "Created at",
"LAST_ACTIVITY": "Poslední aktivita" "LAST_ACTIVITY": "Last activity"
}, },
"GROUPS": { "GROUPS": {
"STANDARD_FILTERS": "Standard Filters", "STANDARD_FILTERS": "Standard filters",
"ADDITIONAL_FILTERS": "Additional Filters", "ADDITIONAL_FILTERS": "Additional filters",
"CUSTOM_ATTRIBUTES": "Vlastní atributy" "CUSTOM_ATTRIBUTES": "Custom attributes"
}, },
"CUSTOM_VIEWS": { "CUSTOM_VIEWS": {
"ADD": { "ADD": {
"TITLE": "Do you want to save this filter?", "TITLE": "Do you want to save this filter?",
"LABEL": "Name this filter", "LABEL": "Name this filter",
"PLACEHOLDER": "Enter a name for this filter", "PLACEHOLDER": "Name your filter to refer it later.",
"ERROR_MESSAGE": "Name is required", "ERROR_MESSAGE": "Name is required.",
"SAVE_BUTTON": "Save filter", "SAVE_BUTTON": "Save filter",
"CANCEL_BUTTON": "Zrušit", "CANCEL_BUTTON": "Zrušit",
"API_FOLDERS": { "API_FOLDERS": {
"SUCCESS_MESSAGE": "Folder created successfully", "SUCCESS_MESSAGE": "Folder created successfully.",
"ERROR_MESSAGE": "Error while creating folder" "ERROR_MESSAGE": "Error while creating folder."
}, },
"API_SEGMENTS": { "API_SEGMENTS": {
"SUCCESS_MESSAGE": "Segment created successfully", "SUCCESS_MESSAGE": "Segment created successfully.",
"ERROR_MESSAGE": "Error while creating segment" "ERROR_MESSAGE": "Error while creating segment."
} }
}, },
"EDIT": { "EDIT": {
@@ -83,19 +83,19 @@
"DELETE_BUTTON": "Delete filter", "DELETE_BUTTON": "Delete filter",
"MODAL": { "MODAL": {
"CONFIRM": { "CONFIRM": {
"TITLE": "Potvrdit odstranění", "TITLE": "Confirm deletion",
"MESSAGE": "Are you sure to delete the filter ", "MESSAGE": "Are you sure to delete the filter ",
"YES": "Ano, odstranit", "YES": "Yes, delete",
"NO": "No, Keep it" "NO": "No, keep it"
} }
}, },
"API_FOLDERS": { "API_FOLDERS": {
"SUCCESS_MESSAGE": "Folder deleted successfully", "SUCCESS_MESSAGE": "Folder deleted successfully.",
"ERROR_MESSAGE": "Error while deleting folder" "ERROR_MESSAGE": "Error while deleting folder."
}, },
"API_SEGMENTS": { "API_SEGMENTS": {
"SUCCESS_MESSAGE": "Segment deleted successfully", "SUCCESS_MESSAGE": "Segment deleted successfully.",
"ERROR_MESSAGE": "Error while deleting segment" "ERROR_MESSAGE": "Error while deleting segment."
} }
} }
} }
@@ -1,73 +1,73 @@
{ {
"AGENT_BOTS": { "AGENT_BOTS": {
"HEADER": "Bots", "HEADER": "Bots",
"LOADING_EDITOR": "Loading Editor...", "LOADING_EDITOR": "Loading editor...",
"HEADER_BTN_TXT": "Add Bot Configuration", "HEADER_BTN_TXT": "Add bot configuration",
"SIDEBAR_TXT": "<p><b>Agent Bots</b> <p>Agent bots allows you to automate the conversations</p>", "SIDEBAR_TXT": "<p><b>Agent Bots</b> <p>Agent Bots are like the most fabulous members of your team. They can handle the small stuff, so you can focus on the stuff that matters. Give them a try.</p> <p> You can manage your bots from this page or create new ones using the 'Add bot configuraton' button.</p> <p> Open the <a href=\"https://www.chatwoot.com/hc/chatwoot-user-guide-cloud-version/articles/1677497472-how-to-use-agent-bots\" target=\"blank\">Agent bots handbook</a> in another tab for a helping hand.</p>",
"CSML_BOT_EDITOR": { "CSML_BOT_EDITOR": {
"NAME": { "NAME": {
"LABEL": "Bot Name", "LABEL": "Bot name",
"PLACEHOLDER": "Give your bot a name", "PLACEHOLDER": "Name your bot.",
"ERROR": "Bot name is required" "ERROR": "Bot name is required."
}, },
"DESCRIPTION": { "DESCRIPTION": {
"LABEL": "Bot Description", "LABEL": "Bot description",
"PLACEHOLDER": "What does this bot do?" "PLACEHOLDER": "What does this bot do?"
}, },
"BOT_CONFIG": { "BOT_CONFIG": {
"ERROR": "Please enter your CSML bot configuration above", "ERROR": "Please enter your CSML bot configuration above.",
"API_ERROR": "Your CSML configuration is invalid, please fix it and try again." "API_ERROR": "Your CSML configuration is invalid. Please fix it and try again."
}, },
"SUBMIT": "Validate and save" "SUBMIT": "Validate and save"
}, },
"BOT_CONFIGURATION": { "BOT_CONFIGURATION": {
"TITLE": "Select an agent bot", "TITLE": "Select an agent bot",
"DESC": "You can set an agent bot from the list to this inbox. The bot can initially handle the conversation and transfer it to an agent when needed.", "DESC": "Assign an Agent Bot to your inbox. They can handle initial conversations and transfer them to a live agent when necessary.",
"SUBMIT": "Aktualizovat", "SUBMIT": "Aktualizovat",
"DISCONNECT": "Disconnect Bot", "DISCONNECT": "Disconnect bot",
"SUCCESS_MESSAGE": "Successfully updated the agent bot", "SUCCESS_MESSAGE": "Successfully updated the agent bot.",
"DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot", "DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot.",
"ERROR_MESSAGE": "Could not update the agent bot, please try again later", "ERROR_MESSAGE": "Could not update the agent bot. Please try again.",
"DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot, please try again later", "DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot. Please try again.",
"SELECT_PLACEHOLDER": "Select Bot" "SELECT_PLACEHOLDER": "Select bot"
}, },
"ADD": { "ADD": {
"TITLE": "Configure new bot", "TITLE": "Configure new bot",
"CANCEL_BUTTON_TEXT": "Zrušit", "CANCEL_BUTTON_TEXT": "Zrušit",
"API": { "API": {
"SUCCESS_MESSAGE": "Bot added successfully", "SUCCESS_MESSAGE": "Bot added successfully.",
"ERROR_MESSAGE": "Could not add bot, Please try again later" "ERROR_MESSAGE": "Could not add bot. Please try again later."
} }
}, },
"LIST": { "LIST": {
"404": "No Bots found, you can create a bot by clicking the 'Configure new bot' Button ↗", "404": "No bots found. You can create a bot by clicking the 'Configure new bot' button ↗",
"LOADING": "Fetching Bots...", "LOADING": "Fetching bots...",
"TYPE": "Bot Type" "TYPE": "Bot type"
}, },
"DELETE": { "DELETE": {
"BUTTON_TEXT": "Vymazat", "BUTTON_TEXT": "Vymazat",
"TITLE": "Delete Bot", "TITLE": "Delete bot",
"SUBMIT": "Vymazat", "SUBMIT": "Vymazat",
"CANCEL_BUTTON_TEXT": "Zrušit", "CANCEL_BUTTON_TEXT": "Zrušit",
"DESCRIPTION": "Are you sure you want to delete this bot? This action is irreversible", "DESCRIPTION": "Are you sure you want to delete this bot? This action is irreversible.",
"API": { "API": {
"SUCCESS_MESSAGE": "Bot deleted successfully", "SUCCESS_MESSAGE": "Bot deleted successfully.",
"ERROR_MESSAGE": "Could not able to delete bot, Please try again later" "ERROR_MESSAGE": "Could not delete bot. Please try again."
} }
}, },
"EDIT": { "EDIT": {
"BUTTON_TEXT": "Upravit", "BUTTON_TEXT": "Upravit",
"LOADING": "Fetching Bots...", "LOADING": "Fetching bots...",
"TITLE": "Edit Bot", "TITLE": "Edit bot",
"CANCEL_BUTTON_TEXT": "Zrušit", "CANCEL_BUTTON_TEXT": "Zrušit",
"API": { "API": {
"SUCCESS_MESSAGE": "Bot updated successfully", "SUCCESS_MESSAGE": "Bot updated successfully.",
"ERROR_MESSAGE": "Could not update bot, Please try again later" "ERROR_MESSAGE": "Could not update bot. Please try again."
} }
}, },
"TYPES": { "TYPES": {
"WEBHOOK": "Webhook Bot", "WEBHOOK": "Webhook bot",
"CSML": "CSML Bot" "CSML": "CSML bot"
} }
} }
} }
@@ -7,34 +7,34 @@
"GO_BACK_LABEL": "Go back", "GO_BACK_LABEL": "Go back",
"ASSIGN_LABEL": "Přiřadit", "ASSIGN_LABEL": "Přiřadit",
"YES": "Ano", "YES": "Ano",
"ASSIGN_AGENT_TOOLTIP": "Assign Agent", "ASSIGN_AGENT_TOOLTIP": "Přiřadit agenta",
"ASSIGN_TEAM_TOOLTIP": "Přiřadit tým", "ASSIGN_TEAM_TOOLTIP": "Přiřadit tým",
"ASSIGN_SUCCESFUL": "Conversations assigned successfully", "ASSIGN_SUCCESFUL": "Conversations assigned successfully.",
"ASSIGN_FAILED": "Failed to assign conversations, please try again", "ASSIGN_FAILED": "Failed to assign conversations. Please try again.",
"RESOLVE_SUCCESFUL": "Conversations resolved successfully", "RESOLVE_SUCCESFUL": "Conversations resolved successfully.",
"RESOLVE_FAILED": "Failed to resolve conversations, please try again", "RESOLVE_FAILED": "Failed to resolve conversations. Please try again.",
"ALL_CONVERSATIONS_SELECTED_ALERT": "Conversations visible on this page are only selected.", "ALL_CONVERSATIONS_SELECTED_ALERT": "Conversations visible on this page are only selected.",
"AGENT_LIST_LOADING": "Loading Agents", "AGENT_LIST_LOADING": "Načítání agentů",
"UPDATE": { "UPDATE": {
"CHANGE_STATUS": "Change status", "CHANGE_STATUS": "Change status",
"SNOOZE_UNTIL_NEXT_REPLY": "Snooze until next reply", "SNOOZE_UNTIL_NEXT_REPLY": "Snooze until next reply.",
"UPDATE_SUCCESFUL": "Conversation status updated successfully.", "UPDATE_SUCCESFUL": "Conversation status updated successfully.",
"UPDATE_FAILED": "Failed to update conversations, please try again" "UPDATE_FAILED": "Failed to update conversations. Please try again."
}, },
"LABELS": { "LABELS": {
"ASSIGN_LABELS": "Assign Labels", "ASSIGN_LABELS": "Assign labels",
"NO_LABELS_FOUND": "No labels found for", "NO_LABELS_FOUND": "No labels found for",
"ASSIGN_SELECTED_LABELS": "Assign selected labels", "ASSIGN_SELECTED_LABELS": "Assign selected labels",
"ASSIGN_SUCCESFUL": "Labels assigned successfully", "ASSIGN_SUCCESFUL": "Labels assigned successfully.",
"ASSIGN_FAILED": "Failed to assign labels, please try again" "ASSIGN_FAILED": "Failed to assign labels. Please try again."
}, },
"TEAMS": { "TEAMS": {
"TEAM_SELECT_LABEL": "Select Team", "TEAM_SELECT_LABEL": "Vybrat tým",
"NONE": "Nic", "NONE": "Nic",
"NO_TEAMS_AVAILABLE": "There are no teams added to this account yet.", "NO_TEAMS_AVAILABLE": "There are no teams added to this account yet.",
"ASSIGN_SELECTED_TEAMS": "Assign selected team", "ASSIGN_SELECTED_TEAMS": "Assign selected team.",
"ASSIGN_SUCCESFUL": "Teams assiged successfully", "ASSIGN_SUCCESFUL": "Teams assiged successfully.",
"ASSIGN_FAILED": "Failed to assign team, please try again" "ASSIGN_FAILED": "Failed to assign team. Please try again."
} }
} }
} }
@@ -1,75 +1,75 @@
{ {
"CANNED_MGMT": { "CANNED_MGMT": {
"HEADER": "Konzervované odpovědi", "HEADER": "Konzervované odpovědi",
"HEADER_BTN_TXT": "Přidat konzervovanou odpověď", "HEADER_BTN_TXT": "Add canned response",
"LOADING": "Načítání Konzervovaných odpovědí", "LOADING": "Fetching canned responses...",
"SEARCH_404": "Neexistují žádné položky odpovídající tomuto dotazu", "SEARCH_404": "Neexistují žádné položky odpovídající tomuto dotazu.",
"SIDEBAR_TXT": "<p><b>Canned Responses</b> </p><p> Canned Responses are saved reply templates which can be used to quickly send out a reply to a conversation. </p><p> For creating a Canned Response, just click on the <b>Add Canned Response</b>. You can also edit or delete an existing Canned Response by clicking on the Edit or Delete button </p><p> Canned responses are used with the help of <b>Short Codes</b>. Agents can access canned responses while on a chat by typing <b>'/'</b> followed by the short code. </p>", "SIDEBAR_TXT": "<p><b>Canned Responses</b> </p><p> Canned Responses are pre-written reply templates that help you quickly respond to a conversation. To insert a canned response during a chat, agents can type a short code preceded by a '/' character. </p><p> You can manage your canned responses from this page or create new ones using the \"Add canned response\" button.</p><p>Open the <a target=\"_blank\" href=\"https://www.chatwoot.com/hc/chatwoot-user-guide-cloud-version/articles/1677501325-how-to-create-saved-reply-templates-with-canned-responses\">Canned Responses handbook</a> in another tab for a helping hand.</p><p>Also, check out the all-new <a href=\"https://www.chatwoot.com/tools/canned-responses-library\" target=\"_blank\">Canned Responses Library</a>.</p>",
"LIST": { "LIST": {
"404": "V tomto účtu nejsou k dispozici žádné konzervované odpovědi.", "404": "V tomto účtu nejsou k dispozici žádné konzervované odpovědi.",
"TITLE": "Spravovat konzervované odpovědi", "TITLE": "Spravovat konzervované odpovědi",
"DESC": "Konzervované odpovědi jsou předdefinované šablony odpovědí, které lze použít k rychlému zasílání odpovědí na tikety.", "DESC": "Canned Responses are predefined reply templates which can be used to quickly send out replies to conversations.",
"TABLE_HEADER": [ "TABLE_HEADER": [
"Krátký kód", "Short code",
"Obsah", "Obsah",
"Akce" "Akce"
] ]
}, },
"ADD": { "ADD": {
"TITLE": "Přidat konzervovanou odpověď", "TITLE": "Add canned response",
"DESC": "Canned Responses are saved reply templates which can be used to quickly send out reply to conversation.", "DESC": "Canned Responses are predefined reply templates which can be used to quickly send out replies to conversations.",
"CANCEL_BUTTON_TEXT": "Zrušit", "CANCEL_BUTTON_TEXT": "Zrušit",
"FORM": { "FORM": {
"SHORT_CODE": { "SHORT_CODE": {
"LABEL": "Krátký kód", "LABEL": "Short code",
"PLACEHOLDER": "Please enter a short code", "PLACEHOLDER": "Please enter a short code.",
"ERROR": "Krátký kód je povinný" "ERROR": "Short Code is required."
}, },
"CONTENT": { "CONTENT": {
"LABEL": "Obsah", "LABEL": "Zpráva",
"PLACEHOLDER": "Zadejte prosím obsah", "PLACEHOLDER": "Please write the message you want to save as a template to use later.",
"ERROR": "Je vyžadován obsah" "ERROR": "Message is required."
}, },
"SUBMIT": "Odeslat" "SUBMIT": "Odeslat"
}, },
"API": { "API": {
"SUCCESS_MESSAGE": "Odpověď v konzervě byla úspěšně přidána", "SUCCESS_MESSAGE": "Canned response added successfully.",
"ERROR_MESSAGE": "Nelze se připojit k Woot serveru, opakujte akci později" "ERROR_MESSAGE": "Nelze se připojit k Woot serveru, opakujte akci později"
} }
}, },
"EDIT": { "EDIT": {
"TITLE": "Upravit konzervovanou odpověď", "TITLE": "Edit canned response",
"CANCEL_BUTTON_TEXT": "Zrušit", "CANCEL_BUTTON_TEXT": "Zrušit",
"FORM": { "FORM": {
"SHORT_CODE": { "SHORT_CODE": {
"LABEL": "Krátký kód", "LABEL": "Short code",
"PLACEHOLDER": "Zadejte zkratkový kód", "PLACEHOLDER": "Please enter a shortcode.",
"ERROR": "Krátký kód je povinný" "ERROR": "Short code is required."
}, },
"CONTENT": { "CONTENT": {
"LABEL": "Obsah", "LABEL": "Zpráva",
"PLACEHOLDER": "Zadejte prosím obsah", "PLACEHOLDER": "Please write the message you want to save as a template to use later.",
"ERROR": "Je vyžadován obsah" "ERROR": "Message is required."
}, },
"SUBMIT": "Odeslat" "SUBMIT": "Odeslat"
}, },
"BUTTON_TEXT": "Upravit", "BUTTON_TEXT": "Upravit",
"API": { "API": {
"SUCCESS_MESSAGE": "Reakce v konzervě byla úspěšně aktualizována", "SUCCESS_MESSAGE": "Canned response is updated successfully.",
"ERROR_MESSAGE": "Nelze se připojit k Woot serveru, opakujte akci později" "ERROR_MESSAGE": "Nelze se připojit k Woot serveru, opakujte akci později"
} }
}, },
"DELETE": { "DELETE": {
"BUTTON_TEXT": "Vymazat", "BUTTON_TEXT": "Vymazat",
"API": { "API": {
"SUCCESS_MESSAGE": "Odpověď v konzervě byla úspěšně odstraněna", "SUCCESS_MESSAGE": "Canned response deleted successfully.",
"ERROR_MESSAGE": "Nelze se připojit k Woot serveru, opakujte akci později" "ERROR_MESSAGE": "Nelze se připojit k Woot serveru, opakujte akci později"
}, },
"CONFIRM": { "CONFIRM": {
"TITLE": "Potvrdit odstranění", "TITLE": "Confirm deletion",
"MESSAGE": "Opravdu chcete odstranit ", "MESSAGE": "Opravdu chcete odstranit ",
"YES": "Ano, odstranit ", "YES": "Yes, delete ",
"NO": "Ne, zachovat " "NO": "No, keep "
} }
} }
} }
@@ -51,18 +51,30 @@
"ACTIVE": "Last activity" "ACTIVE": "Last activity"
} }
}, },
"CHAT_SORT_FILTER_ITEMS": { "SORT_ORDER_ITEMS": {
"latest": { "last_activity_at_asc": {
"TEXT": "Last activity" "TEXT": "Last activity: Oldest first"
}, },
"sort_on_created_at": { "last_activity_at_desc": {
"TEXT": "Created at" "TEXT": "Last activity: Newest first"
}, },
"sort_on_priority": { "created_at_desc": {
"TEXT": "Priority" "TEXT": "Created at: Newest first"
}, },
"sort_on_waiting_since": { "created_at_asc": {
"TEXT": "Pending Response" "TEXT": "Created at: Oldest first"
},
"priority_desc": {
"TEXT": "Priority: Highest first"
},
"priority_asc": {
"TEXT": "Priority: Lowest first"
},
"waiting_since_asc": {
"TEXT": "Pending Response: Longest first"
},
"waiting_since_desc": {
"TEXT": "Pending Response: Shortest first"
} }
}, },
"ATTACHMENTS": { "ATTACHMENTS": {
@@ -41,6 +41,9 @@
"SAVE_CONTACT": "Save", "SAVE_CONTACT": "Save",
"UPLOADING_ATTACHMENTS": "Nahrávání příloh...", "UPLOADING_ATTACHMENTS": "Nahrávání příloh...",
"REPLIED_TO_STORY": "Replied to your story", "REPLIED_TO_STORY": "Replied to your story",
"UNSUPPORTED_MESSAGE": "This message is unsupported.",
"UNSUPPORTED_MESSAGE_FACEBOOK": "This message is unsupported. You can view this message on the Facebook Messenger app.",
"UNSUPPORTED_MESSAGE_INSTAGRAM": "This message is unsupported. You can view this message on the Instagram app.",
"SUCCESS_DELETE_MESSAGE": "Zpráva byla úspěšně smazána", "SUCCESS_DELETE_MESSAGE": "Zpráva byla úspěšně smazána",
"FAIL_DELETE_MESSSAGE": "Zpráva se nepodařilo odstranit! Zkuste to znovu", "FAIL_DELETE_MESSSAGE": "Zpráva se nepodařilo odstranit! Zkuste to znovu",
"NO_RESPONSE": "Bez odpovědi", "NO_RESPONSE": "Bez odpovědi",
@@ -139,6 +142,7 @@
"PRIVATE_NOTE": "Soukromá poznámka", "PRIVATE_NOTE": "Soukromá poznámka",
"SEND": "Poslat", "SEND": "Poslat",
"CREATE": "Přidat poznámku", "CREATE": "Přidat poznámku",
"INSERT_READ_MORE": "Read more",
"DISMISS_REPLY": "Dismiss reply", "DISMISS_REPLY": "Dismiss reply",
"REPLYING_TO": "Replying to:", "REPLYING_TO": "Replying to:",
"TIP_FORMAT_ICON": "Zobrazit formátovaný textový editor", "TIP_FORMAT_ICON": "Zobrazit formátovaný textový editor",

Some files were not shown because too many files have changed in this diff Show More