Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8fc8e95404 | ||
|
|
4201bc965e | ||
|
|
b7db7811d4 | ||
|
|
b411752612 | ||
|
|
20f27b6edf | ||
|
|
5a72f4d0c8 | ||
|
|
e911afe7f6 | ||
|
|
d3a8e83a95 | ||
|
|
335c06af7a | ||
|
|
8a720f9642 | ||
|
|
3ac946712b |
+196
-112
@@ -1,117 +1,117 @@
|
||||
version: 2.1
|
||||
orbs:
|
||||
node: circleci/node@6.1.0
|
||||
ruby: circleci/ruby@2.1.0
|
||||
|
||||
defaults: &defaults
|
||||
working_directory: ~/build
|
||||
machine:
|
||||
image: ubuntu-2204:2024.05.1
|
||||
resource_class: large
|
||||
environment:
|
||||
RAILS_LOG_TO_STDOUT: false
|
||||
COVERAGE: true
|
||||
LOG_LEVEL: warn
|
||||
parallelism: 4
|
||||
executors:
|
||||
app-executor:
|
||||
machine:
|
||||
image: ubuntu-2204:2024.05.1
|
||||
resource_class: large
|
||||
environment:
|
||||
RAILS_LOG_TO_STDOUT: false
|
||||
COVERAGE: true
|
||||
LOG_LEVEL: warn
|
||||
|
||||
jobs:
|
||||
build:
|
||||
<<: *defaults
|
||||
commands:
|
||||
setup_dependencies:
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
# Setup Node with caching
|
||||
- node/install:
|
||||
node-version: '23.7'
|
||||
- node/install-pnpm
|
||||
- restore_cache:
|
||||
keys:
|
||||
- pnpm-deps-v1-{{ checksum "pnpm-lock.yaml" }}
|
||||
- node/install-packages:
|
||||
pkg-manager: pnpm
|
||||
override-ci-command: pnpm i
|
||||
- run: node --version
|
||||
- run: pnpm --version
|
||||
- save_cache:
|
||||
key: pnpm-deps-v1-{{ checksum "pnpm-lock.yaml" }}
|
||||
paths:
|
||||
- node_modules
|
||||
|
||||
# Setup Ruby with caching
|
||||
- ruby/install:
|
||||
version: '3.3.3'
|
||||
- restore_cache:
|
||||
keys:
|
||||
- gem-cache-v1-{{ checksum "Gemfile.lock" }}
|
||||
- run:
|
||||
name: Add PostgreSQL repository and update
|
||||
name: Install Bundler and Gems
|
||||
command: |
|
||||
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
|
||||
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
|
||||
sudo apt-get update -y
|
||||
|
||||
gem install bundler -v 2.5.16
|
||||
bundle config set --local path 'vendor/bundle'
|
||||
bundle install --jobs=4 --retry=3
|
||||
- save_cache:
|
||||
key: gem-cache-v1-{{ checksum "Gemfile.lock" }}
|
||||
paths:
|
||||
- vendor/bundle
|
||||
|
||||
# Install system dependencies using a layer caching approach
|
||||
- restore_cache:
|
||||
keys:
|
||||
- apt-cache-v1-{{ checksum ".circleci/apt-packages.txt" }}
|
||||
- run:
|
||||
name: Create apt packages list
|
||||
command: |
|
||||
mkdir -p .circleci
|
||||
cat > .circleci/apt-packages.txt \<< EOF
|
||||
libpq-dev
|
||||
redis-server
|
||||
postgresql-common
|
||||
postgresql-16
|
||||
postgresql-16-pgvector
|
||||
build-essential
|
||||
git
|
||||
curl
|
||||
libssl-dev
|
||||
zlib1g-dev
|
||||
libreadline-dev
|
||||
libyaml-dev
|
||||
openjdk-11-jdk
|
||||
jq
|
||||
software-properties-common
|
||||
ca-certificates
|
||||
imagemagick
|
||||
libxml2-dev
|
||||
libxslt1-dev
|
||||
file
|
||||
g++
|
||||
gcc
|
||||
autoconf
|
||||
gnupg2
|
||||
patch
|
||||
ruby-dev
|
||||
liblzma-dev
|
||||
libgmp-dev
|
||||
libncurses5-dev
|
||||
libffi-dev
|
||||
libgdbm6
|
||||
libgdbm-dev
|
||||
libvips
|
||||
EOF
|
||||
- run:
|
||||
name: Install System Dependencies
|
||||
command: |
|
||||
sudo apt-get update
|
||||
DEBIAN_FRONTEND=noninteractive sudo apt-get install -y \
|
||||
libpq-dev \
|
||||
redis-server \
|
||||
postgresql-common \
|
||||
postgresql-16 \
|
||||
postgresql-16-pgvector \
|
||||
build-essential \
|
||||
git \
|
||||
curl \
|
||||
libssl-dev \
|
||||
zlib1g-dev \
|
||||
libreadline-dev \
|
||||
libyaml-dev \
|
||||
openjdk-11-jdk \
|
||||
jq \
|
||||
software-properties-common \
|
||||
ca-certificates \
|
||||
imagemagick \
|
||||
libxml2-dev \
|
||||
libxslt1-dev \
|
||||
file \
|
||||
g++ \
|
||||
gcc \
|
||||
autoconf \
|
||||
gnupg2 \
|
||||
patch \
|
||||
ruby-dev \
|
||||
liblzma-dev \
|
||||
libgmp-dev \
|
||||
libncurses5-dev \
|
||||
libffi-dev \
|
||||
libgdbm6 \
|
||||
libgdbm-dev \
|
||||
libvips
|
||||
|
||||
- run:
|
||||
name: Install RVM and Ruby 3.3.3
|
||||
command: |
|
||||
sudo apt-get install -y gpg
|
||||
gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
|
||||
\curl -sSL https://get.rvm.io | bash -s stable
|
||||
echo 'source ~/.rvm/scripts/rvm' >> $BASH_ENV
|
||||
source ~/.rvm/scripts/rvm
|
||||
rvm install "3.3.3"
|
||||
rvm use 3.3.3 --default
|
||||
gem install bundler -v 2.5.16
|
||||
|
||||
- run:
|
||||
name: Install Application Dependencies
|
||||
command: |
|
||||
source ~/.rvm/scripts/rvm
|
||||
bundle install
|
||||
# pnpm install
|
||||
|
||||
- run:
|
||||
name: Download cc-test-reporter
|
||||
command: |
|
||||
mkdir -p ~/tmp
|
||||
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ~/tmp/cc-test-reporter
|
||||
chmod +x ~/tmp/cc-test-reporter
|
||||
|
||||
# Swagger verification
|
||||
- run:
|
||||
name: Verify swagger API specification
|
||||
command: |
|
||||
bundle exec rake swagger:build
|
||||
if [[ `git status swagger/swagger.json --porcelain` ]]
|
||||
then
|
||||
echo "ERROR: The swagger.json file is not in sync with the yaml specification. Run 'rake swagger:build' and commit 'swagger/swagger.json'."
|
||||
exit 1
|
||||
# Add PostgreSQL repository once
|
||||
if [ ! -f /etc/apt/sources.list.d/pgdg.list ]; then
|
||||
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
|
||||
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
|
||||
sudo apt-get update -y
|
||||
fi
|
||||
curl -L https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/6.3.0/openapi-generator-cli-6.3.0.jar > ~/tmp/openapi-generator-cli-6.3.0.jar
|
||||
java -jar ~/tmp/openapi-generator-cli-6.3.0.jar validate -i swagger/swagger.json
|
||||
|
||||
# we remove the FRONTED_URL from the .env before running the tests
|
||||
|
||||
# Install packages
|
||||
DEBIAN_FRONTEND=noninteractive sudo apt-get install -y $(cat .circleci/apt-packages.txt)
|
||||
- save_cache:
|
||||
key: apt-cache-v1-{{ checksum ".circleci/apt-packages.txt" }}
|
||||
paths:
|
||||
- /var/cache/apt
|
||||
|
||||
# Set up database
|
||||
- run:
|
||||
name: Database Setup and Configure Environment Variables
|
||||
command: |
|
||||
@@ -128,39 +128,107 @@ jobs:
|
||||
sed -i -e "/POSTGRES_PASSWORD/ s/=.*/=$pg_pass/" .env
|
||||
echo -en "\nINSTALLATION_ENV=circleci" >> ".env"
|
||||
|
||||
# Database setup
|
||||
# Download code climate reporter just once and cache it
|
||||
- restore_cache:
|
||||
keys:
|
||||
- cc-test-reporter-v1
|
||||
- run:
|
||||
name: Run DB migrations
|
||||
command: bundle exec rails db:chatwoot_prepare
|
||||
name: Download cc-test-reporter
|
||||
command: |
|
||||
if [ ! -f ~/tmp/cc-test-reporter ]; then
|
||||
mkdir -p ~/tmp
|
||||
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ~/tmp/cc-test-reporter
|
||||
chmod +x ~/tmp/cc-test-reporter
|
||||
fi
|
||||
- save_cache:
|
||||
key: cc-test-reporter-v1
|
||||
paths:
|
||||
- ~/tmp/cc-test-reporter
|
||||
|
||||
# Bundle audit
|
||||
workflows:
|
||||
version: 2
|
||||
build_and_test:
|
||||
jobs:
|
||||
- lint
|
||||
- test-frontend:
|
||||
requires:
|
||||
- lint
|
||||
- test-backend:
|
||||
requires:
|
||||
- lint
|
||||
- report-coverage:
|
||||
requires:
|
||||
- test-frontend
|
||||
- test-backend
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
executor: app-executor
|
||||
steps:
|
||||
- setup_dependencies
|
||||
|
||||
# Swagger verification
|
||||
- run:
|
||||
name: Verify swagger API specification
|
||||
command: |
|
||||
bundle exec rake swagger:build
|
||||
if [[ `git status swagger/swagger.json --porcelain` ]]
|
||||
then
|
||||
echo "ERROR: The swagger.json file is not in sync with the yaml specification. Run 'rake swagger:build' and commit 'swagger/swagger.json'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Cache the openapi jar
|
||||
if [ ! -f ~/tmp/openapi-generator-cli-6.3.0.jar ]; then
|
||||
curl -L https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/6.3.0/openapi-generator-cli-6.3.0.jar > ~/tmp/openapi-generator-cli-6.3.0.jar
|
||||
fi
|
||||
java -jar ~/tmp/openapi-generator-cli-6.3.0.jar validate -i swagger/swagger.json
|
||||
|
||||
# Bundle audit - run only in lint job
|
||||
- run:
|
||||
name: Bundle audit
|
||||
command: bundle exec bundle audit update && bundle exec bundle audit check -v
|
||||
|
||||
|
||||
# Rubocop linting
|
||||
- run:
|
||||
name: Rubocop
|
||||
command: bundle exec rubocop
|
||||
|
||||
# ESLint linting
|
||||
|
||||
# ESLint
|
||||
- run:
|
||||
name: eslint
|
||||
command: pnpm run eslint
|
||||
|
||||
test-frontend:
|
||||
executor: app-executor
|
||||
steps:
|
||||
- setup_dependencies
|
||||
- run:
|
||||
name: Run DB migrations
|
||||
command: bundle exec rails db:chatwoot_prepare
|
||||
- run:
|
||||
name: Run frontend tests
|
||||
command: |
|
||||
mkdir -p ~/build/coverage/frontend
|
||||
~/tmp/cc-test-reporter before-build
|
||||
pnpm run test:coverage
|
||||
|
||||
- run:
|
||||
name: Code Climate Test Coverage (Frontend)
|
||||
command: |
|
||||
~/tmp/cc-test-reporter format-coverage -t lcov -o "~/build/coverage/frontend/codeclimate.frontend_$CIRCLE_NODE_INDEX.json"
|
||||
~/tmp/cc-test-reporter format-coverage -t lcov -o "~/build/coverage/frontend/codeclimate.json"
|
||||
- persist_to_workspace:
|
||||
root: ~/build
|
||||
paths:
|
||||
- coverage/frontend
|
||||
|
||||
# Run backend tests
|
||||
test-backend:
|
||||
executor: app-executor
|
||||
parallelism: 4
|
||||
steps:
|
||||
- setup_dependencies
|
||||
- run:
|
||||
name: Run DB migrations
|
||||
command: bundle exec rails db:chatwoot_prepare
|
||||
- run:
|
||||
name: Run backend tests
|
||||
command: |
|
||||
@@ -174,18 +242,34 @@ jobs:
|
||||
--out ~/tmp/test-results/rspec.xml \
|
||||
-- ${TESTFILES}
|
||||
no_output_timeout: 30m
|
||||
|
||||
- run:
|
||||
name: Code Climate Test Coverage (Backend)
|
||||
command: |
|
||||
~/tmp/cc-test-reporter format-coverage -t simplecov -o "~/build/coverage/backend/codeclimate.$CIRCLE_NODE_INDEX.json"
|
||||
|
||||
- run:
|
||||
name: List coverage directory contents
|
||||
command: |
|
||||
ls -R ~/build/coverage
|
||||
|
||||
- persist_to_workspace:
|
||||
root: ~/build
|
||||
paths:
|
||||
- coverage
|
||||
- coverage/backend
|
||||
- store_test_results:
|
||||
path: ~/tmp/test-results
|
||||
- store_artifacts:
|
||||
path: ~/tmp/test-artifacts
|
||||
|
||||
report-coverage:
|
||||
executor: app-executor
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/build
|
||||
- run:
|
||||
name: Download cc-test-reporter
|
||||
command: |
|
||||
mkdir -p ~/tmp
|
||||
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ~/tmp/cc-test-reporter
|
||||
chmod +x ~/tmp/cc-test-reporter
|
||||
- run:
|
||||
name: Upload coverage results to Code Climate
|
||||
command: |
|
||||
# Sum the coverage reports
|
||||
~/tmp/cc-test-reporter sum-coverage ~/build/coverage/**/codeclimate*.json -p 5 -o ~/build/coverage/codeclimate.json
|
||||
# Upload the combined report
|
||||
~/tmp/cc-test-reporter upload-coverage -i ~/build/coverage/codeclimate.json
|
||||
+1
-1
@@ -561,7 +561,7 @@ GEM
|
||||
activesupport (>= 3.0.0)
|
||||
raabro (1.4.0)
|
||||
racc (1.8.1)
|
||||
rack (2.2.13)
|
||||
rack (2.2.12)
|
||||
rack-attack (6.7.0)
|
||||
rack (>= 1.0, < 4)
|
||||
rack-contrib (2.5.0)
|
||||
|
||||
@@ -2,9 +2,10 @@ class RoomChannel < ApplicationCable::Channel
|
||||
def subscribed
|
||||
# TODO: should we only do ensure stream if current account is present?
|
||||
# for now going ahead with guard clauses in update_subscription and broadcast_presence
|
||||
|
||||
ensure_stream
|
||||
current_user
|
||||
current_account
|
||||
prepare_stream
|
||||
update_subscription
|
||||
broadcast_presence
|
||||
end
|
||||
@@ -21,21 +22,12 @@ class RoomChannel < ApplicationCable::Channel
|
||||
|
||||
data = { account_id: @current_account.id, users: ::OnlineStatusTracker.get_available_users(@current_account.id) }
|
||||
data[:contacts] = ::OnlineStatusTracker.get_available_contacts(@current_account.id) if @current_user.is_a? User
|
||||
ActionCable.server.broadcast(pubsub_token, { event: 'presence.update', data: data })
|
||||
ActionCable.server.broadcast(@pubsub_token, { event: 'presence.update', data: data })
|
||||
end
|
||||
|
||||
def prepare_stream
|
||||
stream_from pubsub_token
|
||||
stream_from "account_#{@current_account.id}" if @current_account.present? && @current_user.is_a?(User)
|
||||
stream_from_inboxes
|
||||
end
|
||||
|
||||
def stream_from_inboxes
|
||||
return if current_user.blank?
|
||||
|
||||
current_user.assigned_inboxes.each do |inbox|
|
||||
stream_from "inbox_#{inbox.id}"
|
||||
end
|
||||
def ensure_stream
|
||||
@pubsub_token = params[:pubsub_token]
|
||||
stream_from @pubsub_token
|
||||
end
|
||||
|
||||
def update_subscription
|
||||
@@ -44,15 +36,11 @@ class RoomChannel < ApplicationCable::Channel
|
||||
::OnlineStatusTracker.update_presence(@current_account.id, @current_user.class.name, @current_user.id)
|
||||
end
|
||||
|
||||
def pubsub_token
|
||||
@pubsub_token ||= params[:pubsub_token]
|
||||
end
|
||||
|
||||
def current_user
|
||||
@current_user ||= if params[:user_id].blank?
|
||||
ContactInbox.find_by!(pubsub_token: pubsub_token).contact
|
||||
ContactInbox.find_by!(pubsub_token: @pubsub_token).contact
|
||||
else
|
||||
User.find_by!(pubsub_token: pubsub_token, id: params[:user_id])
|
||||
User.find_by!(pubsub_token: @pubsub_token, id: params[:user_id])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
|
||||
before_action :conversation, except: [:index, :meta, :search, :create, :filter]
|
||||
before_action :inbox, :contact, :contact_inbox, only: [:create]
|
||||
|
||||
ATTACHMENT_RESULTS_PER_PAGE = 100
|
||||
|
||||
def index
|
||||
result = conversation_finder.perform
|
||||
@conversations = result[:conversations]
|
||||
@@ -26,12 +24,7 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
|
||||
end
|
||||
|
||||
def attachments
|
||||
@attachments_count = @conversation.attachments.count
|
||||
@attachments = @conversation.attachments
|
||||
.includes(:message)
|
||||
.order(created_at: :desc)
|
||||
.page(attachment_params[:page])
|
||||
.per(ATTACHMENT_RESULTS_PER_PAGE)
|
||||
end
|
||||
|
||||
def show; end
|
||||
@@ -131,10 +124,6 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
|
||||
params.permit(:priority)
|
||||
end
|
||||
|
||||
def attachment_params
|
||||
params.permit(:page)
|
||||
end
|
||||
|
||||
def update_last_seen_on_conversation(last_seen_at, update_assignee)
|
||||
# rubocop:disable Rails/SkipsModelValidations
|
||||
@conversation.update_column(:agent_last_seen_at, last_seen_at)
|
||||
|
||||
@@ -2,12 +2,6 @@ class Webhooks::WhatsappController < ActionController::API
|
||||
include MetaTokenVerifyConcern
|
||||
|
||||
def process_payload
|
||||
if inactive_whatsapp_number?
|
||||
Rails.logger.warn("Rejected webhook for inactive WhatsApp number: #{params[:phone_number]}")
|
||||
render json: { error: 'Inactive WhatsApp number' }, status: :unprocessable_entity
|
||||
return
|
||||
end
|
||||
|
||||
Webhooks::WhatsappEventsJob.perform_later(params.to_unsafe_hash)
|
||||
head :ok
|
||||
end
|
||||
@@ -19,15 +13,4 @@ class Webhooks::WhatsappController < ActionController::API
|
||||
whatsapp_webhook_verify_token = channel.provider_config['webhook_verify_token'] if channel.present?
|
||||
token == whatsapp_webhook_verify_token if whatsapp_webhook_verify_token.present?
|
||||
end
|
||||
|
||||
def inactive_whatsapp_number?
|
||||
phone_number = params[:phone_number]
|
||||
return false if phone_number.blank?
|
||||
|
||||
inactive_numbers = GlobalConfig.get_value('INACTIVE_WHATSAPP_NUMBERS').to_s
|
||||
return false if inactive_numbers.blank?
|
||||
|
||||
inactive_numbers_array = inactive_numbers.split(',').map(&:strip)
|
||||
inactive_numbers_array.include?(phone_number)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
/* global axios */
|
||||
import ApiClient from './ApiClient';
|
||||
|
||||
class LiveReportsAPI extends ApiClient {
|
||||
constructor() {
|
||||
super('live_reports', { accountScoped: true, apiVersion: 'v2' });
|
||||
}
|
||||
|
||||
getConversationMetric(params = {}) {
|
||||
return axios.get(`${this.url}/conversation_metrics`, { params });
|
||||
}
|
||||
|
||||
getGroupedConversations({ groupBy } = { groupBy: 'assignee_id' }) {
|
||||
return axios.get(`${this.url}/grouped_conversation_metrics`, {
|
||||
params: { group_by: groupBy },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new LiveReportsAPI();
|
||||
@@ -82,7 +82,7 @@ input[type='url']:not(.reset-base) {
|
||||
}
|
||||
|
||||
input[type='file'] {
|
||||
@apply bg-n-background leading-[1.15] mb-4;
|
||||
@apply bg-white dark:bg-n-solid-1 leading-[1.15] mb-4;
|
||||
}
|
||||
|
||||
// Select
|
||||
|
||||
@@ -29,10 +29,6 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
labelClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['action']);
|
||||
@@ -101,13 +97,9 @@ onMounted(() => {
|
||||
</slot>
|
||||
<Icon v-if="item.icon" :icon="item.icon" class="flex-shrink-0 size-3.5" />
|
||||
<span v-if="item.emoji" class="flex-shrink-0">{{ item.emoji }}</span>
|
||||
<span
|
||||
v-if="item.label"
|
||||
class="min-w-0 text-sm truncate"
|
||||
:class="labelClass"
|
||||
>
|
||||
{{ item.label }}
|
||||
</span>
|
||||
<span v-if="item.label" class="min-w-0 text-sm truncate">{{
|
||||
item.label
|
||||
}}</span>
|
||||
</button>
|
||||
<div
|
||||
v-if="filteredMenuItems.length === 0"
|
||||
|
||||
@@ -93,7 +93,7 @@ const hasQuotedMessage = computed(() => {
|
||||
<template v-else>
|
||||
<Letter
|
||||
v-if="showQuotedMessage"
|
||||
class-name="prose prose-bubble !max-w-none letter-render"
|
||||
class-name="prose prose-bubble !max-w-none"
|
||||
:allowed-css-properties="[
|
||||
...allowedCssProperties,
|
||||
'transform',
|
||||
@@ -104,7 +104,7 @@ const hasQuotedMessage = computed(() => {
|
||||
/>
|
||||
<Letter
|
||||
v-else
|
||||
class-name="prose prose-bubble !max-w-none letter-render"
|
||||
class-name="prose prose-bubble !max-w-none"
|
||||
:html="unquotedHTML"
|
||||
:allowed-css-properties="[
|
||||
...allowedCssProperties,
|
||||
@@ -143,21 +143,3 @@ const hasQuotedMessage = computed(() => {
|
||||
</section>
|
||||
</BaseBubble>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
// Tailwind resets break the rendering of google drive link in Gmail messages
|
||||
// This fixes it using https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors
|
||||
|
||||
.letter-render [class*='gmail_drive_chip'] {
|
||||
box-sizing: initial;
|
||||
@apply bg-n-slate-4 border-n-slate-6 rounded-md !important;
|
||||
|
||||
a {
|
||||
@apply text-n-slate-12 !important;
|
||||
|
||||
img {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import BaseBubble from 'next/message/bubbles/Base.vue';
|
||||
import FormattedContent from './FormattedContent.vue';
|
||||
import AttachmentChips from 'next/message/chips/AttachmentChips.vue';
|
||||
@@ -9,26 +9,6 @@ import { useMessageContext } from '../../provider.js';
|
||||
const { content, attachments, contentAttributes, messageType } =
|
||||
useMessageContext();
|
||||
|
||||
const hasTranslations = computed(() => {
|
||||
const { translations = {} } = contentAttributes.value;
|
||||
return Object.keys(translations || {}).length > 0;
|
||||
});
|
||||
|
||||
const renderOriginal = ref(false);
|
||||
|
||||
const renderContent = computed(() => {
|
||||
if (renderOriginal.value) {
|
||||
return content.value;
|
||||
}
|
||||
|
||||
if (hasTranslations.value) {
|
||||
const translations = contentAttributes.value.translations;
|
||||
return translations[Object.keys(translations)[0]];
|
||||
}
|
||||
|
||||
return content.value;
|
||||
});
|
||||
|
||||
const isTemplate = computed(() => {
|
||||
return messageType.value === MESSAGE_TYPES.TEMPLATE;
|
||||
});
|
||||
@@ -36,16 +16,6 @@ const isTemplate = computed(() => {
|
||||
const isEmpty = computed(() => {
|
||||
return !content.value && !attachments.value?.length;
|
||||
});
|
||||
|
||||
const viewToggleKey = computed(() => {
|
||||
return renderOriginal.value
|
||||
? 'CONVERSATION.VIEW_TRANSLATED'
|
||||
: 'CONVERSATION.VIEW_ORIGINAL';
|
||||
});
|
||||
|
||||
const handleSeeOriginal = () => {
|
||||
renderOriginal.value = !renderOriginal.value;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -54,16 +24,7 @@ const handleSeeOriginal = () => {
|
||||
<span v-if="isEmpty" class="text-n-slate-11">
|
||||
{{ $t('CONVERSATION.NO_CONTENT') }}
|
||||
</span>
|
||||
<FormattedContent v-if="renderContent" :content="renderContent" />
|
||||
<span class="-mt-3">
|
||||
<span
|
||||
v-if="hasTranslations"
|
||||
class="text-xs text-n-slate-11 cursor-pointer hover:underline"
|
||||
@click="handleSeeOriginal"
|
||||
>
|
||||
{{ $t(viewToggleKey) }}
|
||||
</span>
|
||||
</span>
|
||||
<FormattedContent v-if="content" :content="content" />
|
||||
<AttachmentChips :attachments="attachments" class="gap-2" />
|
||||
<template v-if="isTemplate">
|
||||
<div
|
||||
|
||||
@@ -90,7 +90,7 @@ const sortedInboxes = computed(() =>
|
||||
inboxes.value.slice().sort((a, b) => a.name.localeCompare(b.name))
|
||||
);
|
||||
|
||||
const newReportRoutes = () => [
|
||||
const newReportRoutes = [
|
||||
{
|
||||
name: 'Reports Agent',
|
||||
label: t('SIDEBAR.REPORTS_AGENT'),
|
||||
@@ -116,7 +116,7 @@ const newReportRoutes = () => [
|
||||
},
|
||||
];
|
||||
|
||||
const oldReportRoutes = () => [
|
||||
const oldReportRoutes = [
|
||||
{
|
||||
name: 'Reports Agent',
|
||||
label: t('SIDEBAR.REPORTS_AGENT'),
|
||||
@@ -140,7 +140,7 @@ const oldReportRoutes = () => [
|
||||
];
|
||||
|
||||
const reportRoutes = computed(() =>
|
||||
showV4Routes.value ? newReportRoutes() : oldReportRoutes()
|
||||
showV4Routes.value ? newReportRoutes : oldReportRoutes
|
||||
);
|
||||
|
||||
const menuItems = computed(() => {
|
||||
|
||||
@@ -97,7 +97,7 @@ export default {
|
||||
}
|
||||
|
||||
.step {
|
||||
@apply bg-slate-75 dark:bg-slate-600 rounded-2xl font-medium w-4 left-4 leading-4 z-10 absolute text-center text-white dark:text-white text-xxs top-5;
|
||||
@apply bg-slate-75 dark:bg-slate-600 rounded-2xl font-medium w-4 left-4 leading-4 z-[999] absolute text-center text-white dark:text-white text-xxs top-5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script setup>
|
||||
import Icon from 'next/icon/Icon.vue';
|
||||
import router from '../../routes/index';
|
||||
const props = defineProps({
|
||||
backUrl: {
|
||||
@@ -23,16 +24,24 @@ const goBack = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const buttonStyleClass = props.compact ? 'text-sm' : 'text-base';
|
||||
const buttonStyleClass = props.compact
|
||||
? 'text-sm text-n-slate-11'
|
||||
: 'text-base text-n-blue-text';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
class="flex items-center p-0 font-normal cursor-pointer text-n-slate-11"
|
||||
class="flex items-center p-0 font-normal cursor-pointer gap-1"
|
||||
:class="buttonStyleClass"
|
||||
@click.capture="goBack"
|
||||
>
|
||||
<fluent-icon icon="chevron-left" class="-ml-1" />
|
||||
<Icon
|
||||
icon="i-lucide-chevron-left"
|
||||
class="ltr:-ml-1 rtl:-mr-1"
|
||||
:class="
|
||||
props.compact ? 'text-n-slate-11 size-4' : 'text-n-blue-text size-5'
|
||||
"
|
||||
/>
|
||||
{{ buttonLabel || $t('GENERAL_SETTINGS.BACK') }}
|
||||
</button>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
contentAttributes: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
emits: ['close'],
|
||||
computed: {
|
||||
translationsAvailable() {
|
||||
return !!Object.keys(this.translations).length;
|
||||
},
|
||||
translations() {
|
||||
return this.contentAttributes.translations || {};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onClose() {
|
||||
this.$emit('close');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<woot-modal
|
||||
modal-type="right-aligned"
|
||||
class="text-left"
|
||||
show
|
||||
:on-close="onClose"
|
||||
>
|
||||
<div class="content">
|
||||
<p>
|
||||
<b>{{ $t('TRANSLATE_MODAL.ORIGINAL_CONTENT') }}</b>
|
||||
</p>
|
||||
<p v-dompurify-html="content" class="mb-0" />
|
||||
<br />
|
||||
<hr />
|
||||
<div v-if="translationsAvailable">
|
||||
<p>
|
||||
<b>{{ $t('TRANSLATE_MODAL.TRANSLATED_CONTENT') }}</b>
|
||||
</p>
|
||||
<div v-for="(translation, language) in translations" :key="language">
|
||||
<p>
|
||||
<strong>{{ language }}:</strong>
|
||||
</p>
|
||||
<p v-dompurify-html="translation" />
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<p v-else>
|
||||
{{ $t('TRANSLATE_MODAL.NO_TRANSLATIONS_AVAILABLE') }}
|
||||
</p>
|
||||
</div>
|
||||
</woot-modal>
|
||||
</template>
|
||||
@@ -5,26 +5,9 @@ import { useMapGetter } from 'dashboard/composables/store';
|
||||
import { allAgentsData, formattedAgentsData } from './fixtures/agentFixtures';
|
||||
import * as agentHelper from 'dashboard/helper/agentHelper';
|
||||
|
||||
// Mock vue-i18n
|
||||
vi.mock('vue-i18n', () => ({
|
||||
useI18n: () => ({
|
||||
t: key => (key === 'AGENT_MGMT.MULTI_SELECTOR.LIST.NONE' ? 'None' : key),
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('dashboard/composables/store');
|
||||
vi.mock('dashboard/helper/agentHelper');
|
||||
|
||||
// Create a mock None agent
|
||||
const mockNoneAgent = {
|
||||
confirmed: true,
|
||||
name: 'None',
|
||||
id: 0,
|
||||
role: 'agent',
|
||||
account_id: 0,
|
||||
email: 'None',
|
||||
};
|
||||
|
||||
const mockUseMapGetter = (overrides = {}) => {
|
||||
const defaultGetters = {
|
||||
getCurrentUser: ref(allAgentsData[0]),
|
||||
@@ -45,6 +28,14 @@ describe('useAgentsList', () => {
|
||||
agentHelper.getSortedAgentsByAvailability.mockReturnValue(
|
||||
formattedAgentsData.slice(1)
|
||||
);
|
||||
agentHelper.getCombinedAgents.mockImplementation(
|
||||
(agents, includeNone, isAgentSelected) => {
|
||||
if (includeNone && isAgentSelected) {
|
||||
return [agentHelper.createNoneAgent, ...agents];
|
||||
}
|
||||
return agents;
|
||||
}
|
||||
);
|
||||
|
||||
mockUseMapGetter();
|
||||
});
|
||||
@@ -53,26 +44,24 @@ describe('useAgentsList', () => {
|
||||
const { agentsList, assignableAgents } = useAgentsList();
|
||||
|
||||
expect(assignableAgents.value).toEqual(allAgentsData);
|
||||
expect(agentsList.value[0]).toEqual(mockNoneAgent);
|
||||
expect(agentsList.value.length).toBe(
|
||||
formattedAgentsData.slice(1).length + 1
|
||||
);
|
||||
expect(agentsList.value).toEqual([
|
||||
agentHelper.createNoneAgent,
|
||||
...formattedAgentsData.slice(1),
|
||||
]);
|
||||
});
|
||||
|
||||
it('includes None agent when includeNoneAgent is true', () => {
|
||||
const { agentsList } = useAgentsList(true);
|
||||
|
||||
expect(agentsList.value[0]).toEqual(mockNoneAgent);
|
||||
expect(agentsList.value.length).toBe(
|
||||
formattedAgentsData.slice(1).length + 1
|
||||
);
|
||||
expect(agentsList.value[0]).toEqual(agentHelper.createNoneAgent);
|
||||
expect(agentsList.value.length).toBe(formattedAgentsData.length);
|
||||
});
|
||||
|
||||
it('excludes None agent when includeNoneAgent is false', () => {
|
||||
const { agentsList } = useAgentsList(false);
|
||||
|
||||
expect(agentsList.value[0].id).not.toBe(0);
|
||||
expect(agentsList.value.length).toBe(formattedAgentsData.slice(1).length);
|
||||
expect(agentsList.value[0]).not.toEqual(agentHelper.createNoneAgent);
|
||||
expect(agentsList.value.length).toBe(formattedAgentsData.length - 1);
|
||||
});
|
||||
|
||||
it('handles empty assignable agents', () => {
|
||||
@@ -84,7 +73,7 @@ describe('useAgentsList', () => {
|
||||
const { agentsList, assignableAgents } = useAgentsList();
|
||||
|
||||
expect(assignableAgents.value).toEqual([]);
|
||||
expect(agentsList.value).toEqual([mockNoneAgent]);
|
||||
expect(agentsList.value).toEqual([agentHelper.createNoneAgent]);
|
||||
});
|
||||
|
||||
it('handles missing inbox_id', () => {
|
||||
@@ -97,6 +86,6 @@ describe('useAgentsList', () => {
|
||||
const { agentsList, assignableAgents } = useAgentsList();
|
||||
|
||||
expect(assignableAgents.value).toEqual([]);
|
||||
expect(agentsList.value).toEqual([mockNoneAgent]);
|
||||
expect(agentsList.value).toEqual([agentHelper.createNoneAgent]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { computed } from 'vue';
|
||||
import { useMapGetter } from 'dashboard/composables/store';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import {
|
||||
getAgentsByUpdatedPresence,
|
||||
getSortedAgentsByAvailability,
|
||||
getCombinedAgents,
|
||||
} from 'dashboard/helper/agentHelper';
|
||||
|
||||
/**
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
* @returns {Object} An object containing the agents list and assignable agents.
|
||||
*/
|
||||
export function useAgentsList(includeNoneAgent = true) {
|
||||
const { t } = useI18n();
|
||||
const currentUser = useMapGetter('getCurrentUser');
|
||||
const currentChat = useMapGetter('getSelectedChat');
|
||||
const currentAccountId = useMapGetter('getCurrentAccountId');
|
||||
@@ -22,19 +21,6 @@ export function useAgentsList(includeNoneAgent = true) {
|
||||
const inboxId = computed(() => currentChat.value?.inbox_id);
|
||||
const isAgentSelected = computed(() => currentChat.value?.meta?.assignee);
|
||||
|
||||
/**
|
||||
* Creates a 'None' agent object
|
||||
* @returns {Object} None agent object
|
||||
*/
|
||||
const createNoneAgent = () => ({
|
||||
confirmed: true,
|
||||
name: t('AGENT_MGMT.MULTI_SELECTOR.LIST.NONE') || 'None',
|
||||
id: 0,
|
||||
role: 'agent',
|
||||
account_id: 0,
|
||||
email: 'None',
|
||||
});
|
||||
|
||||
/**
|
||||
* @type {import('vue').ComputedRef<Array>}
|
||||
*/
|
||||
@@ -57,10 +43,11 @@ export function useAgentsList(includeNoneAgent = true) {
|
||||
agentsByUpdatedPresence
|
||||
);
|
||||
|
||||
return [
|
||||
...(includeNoneAgent && isAgentSelected.value ? [createNoneAgent()] : []),
|
||||
...filteredAgentsByAvailability,
|
||||
];
|
||||
return getCombinedAgents(
|
||||
filteredAgentsByAvailability,
|
||||
includeNoneAgent,
|
||||
isAgentSelected.value
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
export default function useAutomationValues() {
|
||||
const getters = useStoreGetters();
|
||||
const { t } = useI18n();
|
||||
|
||||
const agents = useMapGetter('agents/getAgents');
|
||||
const campaigns = useMapGetter('campaigns/getAllCampaigns');
|
||||
const contacts = useMapGetter('contacts/getContacts');
|
||||
@@ -60,19 +61,6 @@ export default function useAutomationValues() {
|
||||
];
|
||||
});
|
||||
|
||||
/**
|
||||
* Adds a translated "None" option to the beginning of a list
|
||||
* @param {Array} list - The list to add "None" to
|
||||
* @returns {Array} A new array with "None" option at the beginning
|
||||
*/
|
||||
const addNoneToList = list => [
|
||||
{
|
||||
id: 'nil',
|
||||
name: t('AUTOMATION.NONE_OPTION') || 'None',
|
||||
},
|
||||
...(list || []),
|
||||
];
|
||||
|
||||
/**
|
||||
* Gets the condition dropdown values for a given type.
|
||||
* @param {string} type - The type of condition.
|
||||
@@ -107,7 +95,6 @@ export default function useAutomationValues() {
|
||||
slaPolicies: slaPolicies.value,
|
||||
languages,
|
||||
type,
|
||||
addNoneToListFn: addNoneToList,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/**
|
||||
* Default agent object representing 'None'
|
||||
* @type {Object}
|
||||
*/
|
||||
export const createNoneAgent = {
|
||||
confirmed: true,
|
||||
name: 'None',
|
||||
id: 0,
|
||||
role: 'agent',
|
||||
account_id: 0,
|
||||
email: 'None',
|
||||
};
|
||||
|
||||
/**
|
||||
* Filters and sorts agents by availability status
|
||||
* @param {Array} agents - List of agents
|
||||
@@ -49,3 +62,22 @@ export const getAgentsByUpdatedPresence = (
|
||||
);
|
||||
return agentsWithDynamicPresenceUpdate;
|
||||
};
|
||||
|
||||
/**
|
||||
* Combines the filtered agents with the 'None' agent option if applicable.
|
||||
*
|
||||
* @param {Array} filteredAgentsByAvailability - The list of agents sorted by availability.
|
||||
* @param {boolean} includeNoneAgent - Whether to include the 'None' agent option.
|
||||
* @param {boolean} isAgentSelected - Whether an agent is currently selected.
|
||||
* @returns {Array} The combined list of agents, potentially including the 'None' agent.
|
||||
*/
|
||||
export const getCombinedAgents = (
|
||||
filteredAgentsByAvailability,
|
||||
includeNoneAgent,
|
||||
isAgentSelected
|
||||
) => {
|
||||
return [
|
||||
...(includeNoneAgent && isAgentSelected ? [createNoneAgent] : []),
|
||||
...filteredAgentsByAvailability,
|
||||
];
|
||||
};
|
||||
|
||||
@@ -87,7 +87,6 @@ export const generateCustomAttributeTypes = (customAttributes, type) => {
|
||||
};
|
||||
|
||||
export const generateConditionOptions = (options, key = 'id') => {
|
||||
if (!options || !Array.isArray(options)) return [];
|
||||
return options.map(i => {
|
||||
return {
|
||||
id: i[key],
|
||||
@@ -96,17 +95,25 @@ export const generateConditionOptions = (options, key = 'id') => {
|
||||
});
|
||||
};
|
||||
|
||||
// Add the "None" option to the agent list
|
||||
export const addNoneToList = agents => [
|
||||
{
|
||||
id: 'nil',
|
||||
name: 'None',
|
||||
},
|
||||
...(agents || []),
|
||||
];
|
||||
|
||||
export const getActionOptions = ({
|
||||
agents,
|
||||
teams,
|
||||
labels,
|
||||
slaPolicies,
|
||||
type,
|
||||
addNoneToListFn,
|
||||
}) => {
|
||||
const actionsMap = {
|
||||
assign_agent: addNoneToListFn ? addNoneToListFn(agents) : agents,
|
||||
assign_team: addNoneToListFn ? addNoneToListFn(teams) : teams,
|
||||
assign_agent: addNoneToList(agents),
|
||||
assign_team: addNoneToList(teams),
|
||||
send_email_to_team: teams,
|
||||
add_label: generateConditionOptions(labels, 'title'),
|
||||
remove_label: generateConditionOptions(labels, 'title'),
|
||||
|
||||
@@ -2,6 +2,8 @@ import {
|
||||
getAgentsByAvailability,
|
||||
getSortedAgentsByAvailability,
|
||||
getAgentsByUpdatedPresence,
|
||||
getCombinedAgents,
|
||||
createNoneAgent,
|
||||
} from '../agentHelper';
|
||||
import {
|
||||
allAgentsData,
|
||||
@@ -91,4 +93,39 @@ describe('agentHelper', () => {
|
||||
).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCombinedAgents', () => {
|
||||
it('includes None agent when includeNoneAgent is true and isAgentSelected is true', () => {
|
||||
const result = getCombinedAgents(sortedByAvailability, true, true);
|
||||
expect(result).toEqual([createNoneAgent, ...sortedByAvailability]);
|
||||
expect(result.length).toBe(sortedByAvailability.length + 1);
|
||||
expect(result[0]).toEqual(createNoneAgent);
|
||||
});
|
||||
|
||||
it('excludes None agent when includeNoneAgent is false', () => {
|
||||
const result = getCombinedAgents(sortedByAvailability, false, true);
|
||||
expect(result).toEqual(sortedByAvailability);
|
||||
expect(result.length).toBe(sortedByAvailability.length);
|
||||
expect(result[0]).not.toEqual(createNoneAgent);
|
||||
});
|
||||
|
||||
it('excludes None agent when isAgentSelected is false', () => {
|
||||
const result = getCombinedAgents(sortedByAvailability, true, false);
|
||||
expect(result).toEqual(sortedByAvailability);
|
||||
expect(result.length).toBe(sortedByAvailability.length);
|
||||
expect(result[0]).not.toEqual(createNoneAgent);
|
||||
});
|
||||
|
||||
it('returns only filtered agents when both includeNoneAgent and isAgentSelected are false', () => {
|
||||
const result = getCombinedAgents(sortedByAvailability, false, false);
|
||||
expect(result).toEqual(sortedByAvailability);
|
||||
expect(result.length).toBe(sortedByAvailability.length);
|
||||
});
|
||||
|
||||
it('handles empty filteredAgentsByAvailability array', () => {
|
||||
const result = getCombinedAgents([], true, true);
|
||||
expect(result).toEqual([createNoneAgent]);
|
||||
expect(result.length).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -118,46 +118,6 @@ describe('getActionOptions', () => {
|
||||
expectedOptions
|
||||
);
|
||||
});
|
||||
|
||||
it('adds None option when addNoneToListFn is provided', () => {
|
||||
const mockAddNoneToListFn = list => [
|
||||
{ id: 'nil', name: 'None' },
|
||||
...(list || []),
|
||||
];
|
||||
|
||||
const agents = [
|
||||
{ id: 1, name: 'Agent 1' },
|
||||
{ id: 2, name: 'Agent 2' },
|
||||
];
|
||||
|
||||
const expectedOptions = [
|
||||
{ id: 'nil', name: 'None' },
|
||||
{ id: 1, name: 'Agent 1' },
|
||||
{ id: 2, name: 'Agent 2' },
|
||||
];
|
||||
|
||||
expect(
|
||||
helpers.getActionOptions({
|
||||
agents,
|
||||
type: 'assign_agent',
|
||||
addNoneToListFn: mockAddNoneToListFn,
|
||||
})
|
||||
).toEqual(expectedOptions);
|
||||
});
|
||||
|
||||
it('does not add None option when addNoneToListFn is not provided', () => {
|
||||
const agents = [
|
||||
{ id: 1, name: 'Agent 1' },
|
||||
{ id: 2, name: 'Agent 2' },
|
||||
];
|
||||
|
||||
expect(
|
||||
helpers.getActionOptions({
|
||||
agents,
|
||||
type: 'assign_agent',
|
||||
})
|
||||
).toEqual(agents);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getConditionOptions', () => {
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Select agent",
|
||||
"TEAM": "Select team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "None"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "No agents found",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "اختر وكيل",
|
||||
"TEAM": "اختر فريق"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "لا شيء"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "لم يتم العثور على وكلاء",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Select agent",
|
||||
"TEAM": "Select team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "None"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "No agents found",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Изберете агент",
|
||||
"TEAM": "Изберете екип"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Нито един"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Няма намерени агенти",
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
"HEADER": "Agents",
|
||||
"HEADER_BTN_TXT": "Afegir Agent",
|
||||
"LOADING": "S'està recollint la llista d'agents",
|
||||
"DESCRIPTION": "",
|
||||
"LEARN_MORE": "Rakibkazi",
|
||||
"DESCRIPTION": "An agent is a member of your customer support team who can view and respond to user messages. The list below shows all the agents in your account.",
|
||||
"LEARN_MORE": "Learn about user roles",
|
||||
"AGENT_TYPES": {
|
||||
"ADMINISTRATOR": "Administrador/a",
|
||||
"AGENT": "Agent"
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Seleccionar Agent",
|
||||
"TEAM": "Selecciona equip"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Ningú"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "No s'han trobat agents",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Vybrat agenta",
|
||||
"TEAM": "Vybrat tým"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Nic"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Nenalezeni žádní agenti",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Vælg agent",
|
||||
"TEAM": "Vælg hold"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Ingen"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Ingen agenter fundet",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Agent auswählen",
|
||||
"TEAM": "Team auswählen"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Keine"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Keine Agenten gefunden",
|
||||
|
||||
@@ -560,7 +560,7 @@
|
||||
"ERROR_MESSAGE": "Wir konnten die Suche nicht abschließen. Bitte versuch es erneut."
|
||||
},
|
||||
"FORM": {
|
||||
"GO_TO_CONVERSATION": "Anzeigen",
|
||||
"GO_TO_CONVERSATION": "Aussicht",
|
||||
"SUCCESS_MESSAGE": "Die Nachricht wurde erfolgreich versendet!",
|
||||
"ERROR_MESSAGE": "Beim Erstellen der Unterhaltung ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.",
|
||||
"NO_INBOX_ALERT": "Es sind keine Posteingänge vorhanden, um eine Unterhaltung mit diesem Kontakt zu starten.",
|
||||
|
||||
@@ -751,7 +751,7 @@
|
||||
"WHATSAPP": "WhatsApp",
|
||||
"SMS": "SMS",
|
||||
"EMAIL": "E-Mail",
|
||||
"TELEGRAM": "Telegramm",
|
||||
"TELEGRAM": "Telegram",
|
||||
"LINE": "Line",
|
||||
"API": "API-Kanal"
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
},
|
||||
"WEBHOOK": {
|
||||
"SUBSCRIBED_EVENTS": "Abonnierte Events",
|
||||
"LEARN_MORE": "Mehr über Webhooks erfahren",
|
||||
"LEARN_MORE": "Learn more about webhooks",
|
||||
"FORM": {
|
||||
"CANCEL": "Stornieren",
|
||||
"DESC": "Webhook-Ereignisse bieten Ihnen Echtzeitinformationen darüber, was in Ihrem Chatwoot-Konto passiert. Bitte geben Sie eine gültige URL ein, um einen Rückruf zu konfigurieren.",
|
||||
@@ -31,7 +31,7 @@
|
||||
},
|
||||
"END_POINT": {
|
||||
"LABEL": "Webhook-URL",
|
||||
"PLACEHOLDER": "Beispiel: {webhookExampleURL}",
|
||||
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
||||
"ERROR": "Bitte geben Sie eine gültige URL ein"
|
||||
},
|
||||
"EDIT_SUBMIT": "Webhook aktualisieren",
|
||||
@@ -114,7 +114,7 @@
|
||||
},
|
||||
"OPEN_AI": {
|
||||
"AI_ASSIST": "AI-Assistent",
|
||||
"WITH_AI": " {option} mit KI ",
|
||||
"WITH_AI": " {option} with AI ",
|
||||
"OPTIONS": {
|
||||
"REPLY_SUGGESTION": "Antwortvorschlag",
|
||||
"SUMMARIZE": "Zusammenfassen",
|
||||
@@ -235,7 +235,7 @@
|
||||
"ERROR": "Beim Abrufen der linearen Probleme ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut",
|
||||
"LINK_SUCCESS": "Problem erfolgreich verknüpft",
|
||||
"LINK_ERROR": "Beim Verknüpfen des Problems ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut",
|
||||
"LINK_TITLE": "Unterhaltung (#{conversationId}) mit {name}"
|
||||
"LINK_TITLE": "Conversation (#{conversationId}) with {name}"
|
||||
},
|
||||
"ADD_OR_LINK": {
|
||||
"TITLE": "Lineares Problem erstellen/verknüpfen",
|
||||
@@ -294,7 +294,7 @@
|
||||
"PRIORITY": "Priorität",
|
||||
"ASSIGNEE": "Zugewiesener",
|
||||
"LABELS": "Labels",
|
||||
"CREATED_AT": "Erstellt am {createdAt}"
|
||||
"CREATED_AT": "Created at {createdAt}"
|
||||
},
|
||||
"UNLINK": {
|
||||
"TITLE": "Verknüpfung aufheben",
|
||||
@@ -302,8 +302,8 @@
|
||||
"ERROR": "Beim Aufheben der Verknüpfung des Problems ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut"
|
||||
},
|
||||
"DELETE": {
|
||||
"TITLE": "Sind Sie sicher, dass Sie die Integration löschen möchten?",
|
||||
"MESSAGE": "Sind Sie sicher, dass Sie die Integration löschen möchten?",
|
||||
"TITLE": "Are you sure you want to delete the integration?",
|
||||
"MESSAGE": "Are you sure you want to delete the integration?",
|
||||
"CONFIRM": "Ja, löschen",
|
||||
"CANCEL": "Stornieren"
|
||||
}
|
||||
@@ -313,27 +313,27 @@
|
||||
"NAME": "Kapitän",
|
||||
"COPILOT": {
|
||||
"SEND_MESSAGE": "Nachricht senden...",
|
||||
"LOADER": "Captain denkt nach",
|
||||
"LOADER": "Captain is thinking",
|
||||
"YOU": "Sie",
|
||||
"USE": "Verwenden",
|
||||
"RESET": "Zurücksetzen",
|
||||
"SELECT_ASSISTANT": "Assistent auswählen"
|
||||
"USE": "Use this",
|
||||
"RESET": "Reset",
|
||||
"SELECT_ASSISTANT": "Select Assistant"
|
||||
},
|
||||
"PAYWALL": {
|
||||
"TITLE": "Upgrade auf Captain AI",
|
||||
"TITLE": "Upgrade to use Captain AI",
|
||||
"AVAILABLE_ON": "Captain is not available on the free plan.",
|
||||
"UPGRADE_PROMPT": "Tarif upgraden, um Zugang zu unseren Assistenten, Copilot und mehr zu erhalten.",
|
||||
"UPGRADE_NOW": "Jetzt upgraden",
|
||||
"CANCEL_ANYTIME": "Sie können Ihr Paket jederzeit ändern oder kündigen"
|
||||
"UPGRADE_PROMPT": "Upgrade your plan to get access to our assistants, copilot and more.",
|
||||
"UPGRADE_NOW": "Upgrade now",
|
||||
"CANCEL_ANYTIME": "You can change or cancel your plan anytime"
|
||||
},
|
||||
"ENTERPRISE_PAYWALL": {
|
||||
"AVAILABLE_ON": "Captain AI Funktion ist nur mit einem kostenpflichtigen Tarif verfügbar.",
|
||||
"UPGRADE_PROMPT": "Tarif upgraden, um Zugang zu unseren Assistenten, Copilot und mehr zu erhalten.",
|
||||
"ASK_ADMIN": "Bitte kontaktieren Sie Ihren Administrator für das Upgrade."
|
||||
"AVAILABLE_ON": "Captain AI feature is only available in a paid plan.",
|
||||
"UPGRADE_PROMPT": "Upgrade your plan to get access to our assistants, copilot and more.",
|
||||
"ASK_ADMIN": "Please reach out to your administrator for the upgrade."
|
||||
},
|
||||
"BANNER": {
|
||||
"RESPONSES": "You've used over 80% of your response limit. To continue using Captain AI, please upgrade.",
|
||||
"DOCUMENTS": "Dokumentenlimit erreicht. Upgraden um Cpatain AI weiter zu verwenden."
|
||||
"DOCUMENTS": "Document limit reached. Upgrade to continue using Captain AI."
|
||||
},
|
||||
"FORM": {
|
||||
"CANCEL": "Stornieren",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Επιλογή πράκτορα",
|
||||
"TEAM": "Επιλογή ομάδας"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Κανένα"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Δεν βρέθηκαν Πράκτορες",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Select agent",
|
||||
"TEAM": "Select team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "None"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "No agents found",
|
||||
|
||||
@@ -125,7 +125,6 @@
|
||||
"ACTION_PARAMETERS_REQUIRED": "Action parameters are required",
|
||||
"ATLEAST_ONE_CONDITION_REQUIRED": "At least one condition is required",
|
||||
"ATLEAST_ONE_ACTION_REQUIRED": "At least one action is required"
|
||||
},
|
||||
"NONE_OPTION": "None"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
"NO_INBOX_2": " to get started",
|
||||
"NO_INBOX_AGENT": "Uh Oh! Looks like you are not part of any inbox. Please contact your administrator",
|
||||
"SEARCH_MESSAGES": "Search for messages in conversations",
|
||||
"VIEW_ORIGINAL": "View original",
|
||||
"VIEW_TRANSLATED": "View translated",
|
||||
"EMPTY_STATE": {
|
||||
"CMD_BAR": "to open command menu",
|
||||
"KEYBOARD_SHORTCUTS": "to view keyboard shortcuts"
|
||||
|
||||
@@ -476,18 +476,6 @@
|
||||
"STATUS": "Status"
|
||||
}
|
||||
},
|
||||
"TEAM_CONVERSATIONS": {
|
||||
"ALL_TEAMS": "All Teams",
|
||||
"HEADER": "Conversations by teams",
|
||||
"LOADING_MESSAGE": "Loading team metrics...",
|
||||
"NO_TEAMS": "There is no data available",
|
||||
"TABLE_HEADER": {
|
||||
"TEAM": "Team",
|
||||
"OPEN": "Open",
|
||||
"UNATTENDED": "Unattended",
|
||||
"STATUS": "Status"
|
||||
}
|
||||
},
|
||||
"AGENT_STATUS": {
|
||||
"HEADER": "Agent status",
|
||||
"ONLINE": "Online",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Seleccionar agente",
|
||||
"TEAM": "Seleccionar equipo"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Ninguna"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "No se encontraron agentes",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "انتخاب اپراتور",
|
||||
"TEAM": "انتخاب تیم"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "هیچکدام"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "اپراتوری یافت نشد",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Select agent",
|
||||
"TEAM": "Select team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "None"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Edustajia ei löytynyt",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Sélectionner un agent",
|
||||
"TEAM": "Sélectionner une équipe"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Aucun"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Aucun agent trouvé",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "בחר נציג",
|
||||
"TEAM": "בחר קבוצה"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "כלום"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "לא נמצא סוכן",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Select agent",
|
||||
"TEAM": "Select team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "None"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "No agents found",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Select agent",
|
||||
"TEAM": "Select team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Nijedno"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "No agents found",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Ügynök kiválasztása",
|
||||
"TEAM": "Csapat kiválasztása"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Nincs"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Nem találunk ügynököt",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Select agent",
|
||||
"TEAM": "Select team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "None"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "No agents found",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Pilih Agen",
|
||||
"TEAM": "Pilih tim"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Tidak ada"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Tidak ada agen",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Velja þjónustufulltrúa",
|
||||
"TEAM": "Velja teymi"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Enginn"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Engir þjónustufulltrúar fundust",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Seleziona un'agente",
|
||||
"TEAM": "Seleziona team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Nessuno"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Nessun agente trovato",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "担当者を選択",
|
||||
"TEAM": "チームを選択"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "なし"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "担当者が見つかりません",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Select agent",
|
||||
"TEAM": "Select team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "None"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "No agents found",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "에이전트 선택",
|
||||
"TEAM": "팀 선택"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "없음"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "에이전트를 찾을 수 없음",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Pasirinkti agentą",
|
||||
"TEAM": "Pasirinkite komandą"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Nėra"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Agentų nerasta",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Izvēlieties aģentu",
|
||||
"TEAM": "Izvēlieties komandu"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Nav"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Aģenti nav atrasti",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "ഏജന്റിനെ തിരഞ്ഞെടുക്കുക",
|
||||
"TEAM": "ടീം തിരഞ്ഞെടുക്കുക"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "ഒന്നുമില്ല"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "ഏജന്റകളെ ഒന്നും കണ്ടെത്താൻ സാധിച്ചില്ല",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Pilih ejen",
|
||||
"TEAM": "Pilih pasukan"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Tiada"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Tiada ejen dijumpa",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Select agent",
|
||||
"TEAM": "Select team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "None"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "No agents found",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Selecteer agent",
|
||||
"TEAM": "Selecteer team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Geen"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Geen medewerkers gevonden",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Velg agent",
|
||||
"TEAM": "Velg gruppe"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Ingen"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Ingen agenter funnet",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Wybierz konsultanta",
|
||||
"TEAM": "Wybierz zespół"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Brak"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Nie znaleziono agentów",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Escolher agente",
|
||||
"TEAM": "Escolher equipa"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Nenhuma"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Nenhum agente encontrado",
|
||||
|
||||
@@ -100,14 +100,11 @@
|
||||
"NO_RESULTS": "Nenhum resultado encontrado."
|
||||
},
|
||||
"MULTI_SELECTOR": {
|
||||
"PLACEHOLDER": "Nenhum",
|
||||
"PLACEHOLDER": "Nenhuma",
|
||||
"TITLE": {
|
||||
"AGENT": "Selecionar agente",
|
||||
"TEAM": "Selecionar time"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Nenhuma"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Nenhum agente encontrado",
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"AUDIT_LOGS": {
|
||||
"HEADER": "Auditoria",
|
||||
"HEADER_BTN_TXT": "Adicionar Logs de Auditoria",
|
||||
"HEADER": "Registros de Auditoria",
|
||||
"HEADER_BTN_TXT": "Adicionar Registros de Auditoria",
|
||||
"LOADING": "Buscando Logs de Auditoria",
|
||||
"DESCRIPTION": "Logs de Auditoria mantêm um registro de atividades em sua conta, permitindo que você acompanhe e auditore sua conta, equipe ou serviços.",
|
||||
"DESCRIPTION": "Logs de Auditoria mantêm um registro de atividades em sua conta, permitindo que você acompanhe e auditoria de sua conta, equipe ou serviços.",
|
||||
"LEARN_MORE": "Saiba mais sobre os logs de auditoria",
|
||||
"SEARCH_404": "Não existem itens correspondentes a esta consulta",
|
||||
"SIDEBAR_TXT": "<p><b>Logs de Auditoria</b> </p><p> Os Logs de Auditoria são rastros para eventos e ações em um Sistema Chatwoot. </p>",
|
||||
"SIDEBAR_TXT": "<p><b>Registros de Auditoria</b> </p><p> Registros de Auditoria são trilhas para eventos e ações em um Sistema Chatwoot. </p>",
|
||||
"LIST": {
|
||||
"404": "Não há Logs de Auditoria disponíveis nesta conta.",
|
||||
"TITLE": "Gerenciar Logs de Auditoria",
|
||||
"DESC": "Logs de auditoria são rastros para eventos e ações em um Sistema de Chatwoot.",
|
||||
"404": "Não há Registros de Auditoria disponíveis nesta conta.",
|
||||
"TITLE": "Gerenciar Registros de Auditoria",
|
||||
"DESC": "Registros de Auditoria são trilhas para eventos e ações em um Sistema Chatwoot.",
|
||||
"TABLE_HEADER": {
|
||||
"ACTIVITY": "Usuário",
|
||||
"TIME": "Ação",
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
"ERROR": "Falha ao atualizar etiquetas"
|
||||
},
|
||||
"CONVERSATION": {
|
||||
"TITLE": "Etiquetas da conversa",
|
||||
"ADD_BUTTON": "Adicionar etiquetas"
|
||||
"TITLE": "Marcador da conversa",
|
||||
"ADD_BUTTON": "Adicionar marcador"
|
||||
},
|
||||
"LABEL_SELECT": {
|
||||
"TITLE": "Adicionar etiquetas",
|
||||
"PLACEHOLDER": "Pesquisar etiquetas",
|
||||
"TITLE": "Adicionar marcador",
|
||||
"PLACEHOLDER": "Pesquisar marcador ",
|
||||
"NO_RESULT": "Nenhuma etiqueta encontrada",
|
||||
"CREATE_LABEL": "Criar etiqueta"
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"HEADER": {
|
||||
"RESOLVE_ACTION": "Resolver",
|
||||
"REOPEN_ACTION": "Reabrir",
|
||||
"OPEN_ACTION": "Abrir",
|
||||
"OPEN_ACTION": "Abertas",
|
||||
"OPEN": "Mais",
|
||||
"CLOSE": "Fechar",
|
||||
"DETAILS": "detalhes",
|
||||
@@ -148,7 +148,7 @@
|
||||
"MESSAGE_SIGN_TOOLTIP": "Assinatura de mensagem",
|
||||
"ENABLE_SIGN_TOOLTIP": "Ativar assinatura",
|
||||
"DISABLE_SIGN_TOOLTIP": "Desativar assinatura",
|
||||
"MSG_INPUT": "Shift + enter para nova linha. Digite '/' para selecionar uma Resposta Pronta.",
|
||||
"MSG_INPUT": "Shift + enter para nova linha. Digite '/' para atalhos.",
|
||||
"PRIVATE_MSG_INPUT": "A mensagem será visível apenas para agentes",
|
||||
"MESSAGE_SIGNATURE_NOT_CONFIGURED": "A assinatura da mensagem não está configurada. Por favor, configure-a nas configurações do perfil.",
|
||||
"CLICK_HERE": "Clique aqui para atualizar",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"ENTERPRISE_PAYWALL": {
|
||||
"AVAILABLE_ON": "O recurso de função personalizada está disponível apenas nos planos pagos.",
|
||||
"UPGRADE_PROMPT": "Atualize para um plano pago para acessar recursos avançados como logs de auditoria, capacidade do agente e muito mais.",
|
||||
"UPGRADE_PROMPT": "Atualize para um plano pago para acessar recursos avançados como registros de auditoria, capacidade do agente e muito mais.",
|
||||
"ASK_ADMIN": "Entre em contato com seu administrador para fazer a atualização."
|
||||
},
|
||||
"LIST": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"GENERAL_SETTINGS": {
|
||||
"TITLE": "Conta",
|
||||
"TITLE": "Configurações da conta",
|
||||
"SUBMIT": "Atualizar configurações",
|
||||
"BACK": "Anterior",
|
||||
"DISMISS": "Recusar",
|
||||
@@ -131,10 +131,10 @@
|
||||
"GO_TO_INBOX_REPORTS": "Ir para Relatórios da Caixa de Entrada",
|
||||
"GO_TO_TEAM_REPORTS": "Ir para Relatórios da Equipe",
|
||||
"GO_TO_SETTINGS_AGENTS": "Ir para Configurações de Agente",
|
||||
"GO_TO_SETTINGS_TEAMS": "Ir para as Configurações de Equipe",
|
||||
"GO_TO_SETTINGS_INBOXES": "Ir para as Configurações da Caixa de Entrada",
|
||||
"GO_TO_SETTINGS_TEAMS": "Ir para as configurações de equipe",
|
||||
"GO_TO_SETTINGS_INBOXES": "Ir para as configurações da Caixa de Entrada",
|
||||
"GO_TO_SETTINGS_LABELS": "Ir para as Configurações de Etiqueta",
|
||||
"GO_TO_SETTINGS_CANNED_RESPONSES": "Ir para as Configurações de Respostas Prontas",
|
||||
"GO_TO_SETTINGS_CANNED_RESPONSES": "Ir para as configurações de respostas prontas",
|
||||
"GO_TO_SETTINGS_APPLICATIONS": "Vá para Configurações do Aplicativo",
|
||||
"GO_TO_SETTINGS_ACCOUNT": "Ir para as Configurações da Conta",
|
||||
"GO_TO_SETTINGS_PROFILE": "Ir para as Configurações do Perfil",
|
||||
|
||||
@@ -500,7 +500,7 @@
|
||||
"ENABLE_CONTINUITY_VIA_EMAIL_SUB_TEXT": "As conversas continuarão sobre o e-mail se o endereço de e-mail de contato estiver disponível.",
|
||||
"LOCK_TO_SINGLE_CONVERSATION": "Bloquear para conversa única",
|
||||
"LOCK_TO_SINGLE_CONVERSATION_SUB_TEXT": "Ativar ou desativar várias conversas para o mesmo contato nesta caixa de entrada",
|
||||
"INBOX_UPDATE_TITLE": "Configurações da Caixa de Entrada",
|
||||
"INBOX_UPDATE_TITLE": "Configurações da Caixa de entrada",
|
||||
"INBOX_UPDATE_SUB_TEXT": "Atualize suas configurações de caixa de entrada",
|
||||
"AUTO_ASSIGNMENT_SUB_TEXT": "Ativar ou desativar a atribuição automática de novas conversas aos agentes adicionados a essa caixa de entrada.",
|
||||
"HMAC_VERIFICATION": "Validação de Identidade do Usuário",
|
||||
@@ -695,7 +695,7 @@
|
||||
"PLACE_HOLDER": "Fale conosco no chat"
|
||||
},
|
||||
"UPDATE": {
|
||||
"BUTTON_TEXT": "Atualizar Configurações do Widget",
|
||||
"BUTTON_TEXT": "Atualizar configurações do widget",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Configurações do widget atualizadas com sucesso",
|
||||
"ERROR_MESSAGE": "Não é possível atualizar as configurações do widget"
|
||||
|
||||
@@ -302,8 +302,8 @@
|
||||
"ERROR": "Houve um erro ao desvincular o atributo, por favor, tente novamente"
|
||||
},
|
||||
"DELETE": {
|
||||
"TITLE": "Tem certeza que deseja excluir esta integração?",
|
||||
"MESSAGE": "Tem certeza que deseja excluir esta integração?",
|
||||
"TITLE": "Are you sure you want to delete the integration?",
|
||||
"MESSAGE": "Are you sure you want to delete the integration?",
|
||||
"CONFIRM": "Sim, excluir",
|
||||
"CANCEL": "Cancelar"
|
||||
}
|
||||
@@ -317,7 +317,7 @@
|
||||
"YOU": "Você",
|
||||
"USE": "Use isto",
|
||||
"RESET": "Reiniciar",
|
||||
"SELECT_ASSISTANT": "Selecione o Assistente"
|
||||
"SELECT_ASSISTANT": "Select Assistant"
|
||||
},
|
||||
"PAYWALL": {
|
||||
"TITLE": "Atualize para usar o Capitão IA",
|
||||
@@ -440,19 +440,19 @@
|
||||
"DOCUMENTABLE": {
|
||||
"CONVERSATION": "Conversação #{id}"
|
||||
},
|
||||
"SELECTED": "{count} selecionado",
|
||||
"BULK_APPROVE_BUTTON": "Aprovar",
|
||||
"SELECTED": "{count} selected",
|
||||
"BULK_APPROVE_BUTTON": "Approve",
|
||||
"BULK_DELETE_BUTTON": "Excluir",
|
||||
"BULK_APPROVE": {
|
||||
"SUCCESS_MESSAGE": "Perguntas Frequentes aprovadas com sucesso",
|
||||
"ERROR_MESSAGE": "Ocorreu um erro ao aprovar as Perguntas Frequentes. Tente novamente."
|
||||
"SUCCESS_MESSAGE": "FAQs approved successfully",
|
||||
"ERROR_MESSAGE": "There was an error approving the FAQs, please try again."
|
||||
},
|
||||
"BULK_DELETE": {
|
||||
"TITLE": "Excluir as Perguntas Frequentes?",
|
||||
"DESCRIPTION": "Tem certeza que deseja excluir as Perguntas Frequentes selecionadas? Esta ação não pode ser desfeita.",
|
||||
"CONFIRM": "Sim, excluir todas",
|
||||
"SUCCESS_MESSAGE": "Perguntas Frequentes excluídas com sucesso/",
|
||||
"ERROR_MESSAGE": "Ocorreu um erro ao excluir as Perguntas Frequentes, por favor tente novamente."
|
||||
"TITLE": "Delete FAQs?",
|
||||
"DESCRIPTION": "Are you sure you want to delete the selected FAQs? This action cannot be undone.",
|
||||
"CONFIRM": "Yes, delete all",
|
||||
"SUCCESS_MESSAGE": "FAQs deleted successfully",
|
||||
"ERROR_MESSAGE": "There was an error deleting the FAQs, please try again."
|
||||
},
|
||||
"DELETE": {
|
||||
"TITLE": "Tem certeza que deseja excluir o FAQ?",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"LABEL_MGMT": {
|
||||
"HEADER": "Etiquetas",
|
||||
"HEADER_BTN_TXT": "Adicionar etiqueta",
|
||||
"HEADER_BTN_TXT": "Adicionar marcador",
|
||||
"LOADING": "Buscando etiquetas",
|
||||
"DESCRIPTION": "As etiquetas ajudam você a categorizar e priorizar conversas e leads. Você pode atribuir uma etiqueta a uma conversa ou contato usando o painel lateral.",
|
||||
"LEARN_MORE": "Aprenda mais sobre etiquetas",
|
||||
@@ -18,21 +18,21 @@
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Nome da Etiqueta",
|
||||
"PLACEHOLDER": "Nome da etiqueta",
|
||||
"REQUIRED_ERROR": "O nome da etiqueta é obrigatório",
|
||||
"LABEL": "Nome do marcador",
|
||||
"PLACEHOLDER": "Nome do marcador",
|
||||
"REQUIRED_ERROR": "O nome do marcador é obrigatório",
|
||||
"MINIMUM_LENGTH_ERROR": "Tamanho mínimo 2 é necessário",
|
||||
"VALID_ERROR": "Somente Letras, Números, Hífen e Sublinhado são permitidos"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Descrição",
|
||||
"PLACEHOLDER": "Descrição da etiqueta"
|
||||
"PLACEHOLDER": "Descrição do marcador"
|
||||
},
|
||||
"COLOR": {
|
||||
"LABEL": "Cor"
|
||||
},
|
||||
"SHOW_ON_SIDEBAR": {
|
||||
"LABEL": "Exibir etiqueta na barra lateral"
|
||||
"LABEL": "Exibir marcador na barra lateral"
|
||||
},
|
||||
"EDIT": "Alterar",
|
||||
"CREATE": "Criar",
|
||||
@@ -54,10 +54,10 @@
|
||||
"SUGGESTED_LABELS": "Etiquetas sugeridos"
|
||||
},
|
||||
"ADD": {
|
||||
"TITLE": "Adicionar etiqueta",
|
||||
"TITLE": "Adicionar marcador",
|
||||
"DESC": "Etiquetas permitem agrupar as conversas.",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Etiqueta adicionada com sucesso",
|
||||
"SUCCESS_MESSAGE": "Marcador adicionado com sucesso",
|
||||
"ERROR_MESSAGE": "Ocorreu um erro, por favor tente novamente"
|
||||
}
|
||||
},
|
||||
@@ -71,7 +71,7 @@
|
||||
"DELETE": {
|
||||
"BUTTON_TEXT": "Excluir",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Etiqueta excluída com sucesso",
|
||||
"SUCCESS_MESSAGE": "Marcador excluído com sucesso",
|
||||
"ERROR_MESSAGE": "Ocorreu um erro, por favor tente novamente"
|
||||
},
|
||||
"CONFIRM": {
|
||||
|
||||
@@ -471,7 +471,7 @@
|
||||
"NO_AGENTS": "Não há conversas por agentes",
|
||||
"TABLE_HEADER": {
|
||||
"AGENT": "Agente",
|
||||
"OPEN": "Abrir",
|
||||
"OPEN": "Abertas",
|
||||
"UNATTENDED": "Não atendidas",
|
||||
"STATUS": "Situação"
|
||||
}
|
||||
@@ -509,7 +509,7 @@
|
||||
"SLA": "Nome do SLA",
|
||||
"AGENTS": "Nome do Agente",
|
||||
"INBOXES": "Nome da Caixa de Entrada",
|
||||
"LABELS": "Nome da etiqueta",
|
||||
"LABELS": "Nome do marcador",
|
||||
"TEAMS": "Nome da equipe"
|
||||
},
|
||||
"SLA": "Política SLA",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"UPDATE_SUCCESS": "Suas configurações foram atualizadas com sucesso",
|
||||
"CARD": {
|
||||
"ENTER_KEY": {
|
||||
"HEADING": "Enter (↵)",
|
||||
"HEADING": "Inserir (↵)",
|
||||
"CONTENT": "Enviar mensagens pressionando a tecla Enter em vez de clicar no botão de enviar."
|
||||
},
|
||||
"CMD_ENTER_KEY": {
|
||||
@@ -37,19 +37,19 @@
|
||||
},
|
||||
"INTERFACE_SECTION": {
|
||||
"TITLE": "Interface",
|
||||
"NOTE": "Personalize a aparência do seu painel do Chatwoot.",
|
||||
"NOTE": "Customize the look and feel of your Chatwoot dashboard.",
|
||||
"FONT_SIZE": {
|
||||
"TITLE": "Tamanho da fonte",
|
||||
"NOTE": "Ajuste o tamanho do texto do painel com base na sua preferência.",
|
||||
"UPDATE_SUCCESS": "As configurações de sua fonte foram atualizadas com sucesso",
|
||||
"UPDATE_ERROR": "Ocorreu um erro ao atualizar as configurações de fonte, por favor, tente novamente",
|
||||
"TITLE": "Font size",
|
||||
"NOTE": "Adjust the text size across the dashboard based on your preference.",
|
||||
"UPDATE_SUCCESS": "Your font settings have been updated successfully",
|
||||
"UPDATE_ERROR": "There is an error while updating the font settings, please try again",
|
||||
"OPTIONS": {
|
||||
"SMALLER": "Menor",
|
||||
"SMALL": "Pequeno",
|
||||
"SMALLER": "Smaller",
|
||||
"SMALL": "Small",
|
||||
"DEFAULT": "Padrão",
|
||||
"LARGE": "Grande",
|
||||
"LARGER": "Maior",
|
||||
"EXTRA_LARGE": "Muito Grande"
|
||||
"LARGE": "Large",
|
||||
"LARGER": "Larger",
|
||||
"EXTRA_LARGE": "Extra Large"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -287,13 +287,13 @@
|
||||
"HOME": "Principal",
|
||||
"AGENTS": "Agentes",
|
||||
"AGENT_BOTS": "Robôs",
|
||||
"AUDIT_LOGS": "Auditoria",
|
||||
"AUDIT_LOGS": "Registros de Auditoria",
|
||||
"INBOXES": "Caixas de Entrada",
|
||||
"NOTIFICATIONS": "Notificações",
|
||||
"CANNED_RESPONSES": "Respostas Prontas",
|
||||
"INTEGRATIONS": "Integrações",
|
||||
"PROFILE_SETTINGS": "Configurações do Perfil",
|
||||
"ACCOUNT_SETTINGS": "Conta",
|
||||
"ACCOUNT_SETTINGS": "Configurações da conta",
|
||||
"APPLICATIONS": "Aplicações",
|
||||
"LABELS": "Etiquetas",
|
||||
"CUSTOM_ATTRIBUTES": "Atributos Personalizados",
|
||||
@@ -322,7 +322,7 @@
|
||||
"REPORTS_INBOX": "Caixa de Entrada",
|
||||
"REPORTS_TEAM": "Equipe",
|
||||
"SET_AVAILABILITY_TITLE": "Defina como",
|
||||
"SET_YOUR_AVAILABILITY": "Disponibilidade",
|
||||
"SET_YOUR_AVAILABILITY": "Definir a sua disponibilidade",
|
||||
"SLA": "SLA",
|
||||
"CUSTOM_ROLES": "Regras Personalizadas",
|
||||
"BETA": "Beta",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"SLA": {
|
||||
"HEADER": "Acordo de Nível de Serviço",
|
||||
"HEADER": "Termos do Serviço",
|
||||
"ADD_ACTION": "Adicionar SLA",
|
||||
"ADD_ACTION_LONG": "Criar uma nova Política de SLA",
|
||||
"DESCRIPTION": "Acordo de Nível de Serviço (SLAs em inglês) são acordos que definem expectativas claras entre sua equipe e os clientes. Estabelecem normas para tempos de resposta e de resolução, criando um quadro de responsabilização e garantindo uma experiência coerente e de qualidade.",
|
||||
"DESCRIPTION": "Contratos de Nível de Serviço (SLAs em inglês) são contratos que definem expectativas claras entre sua equipe e os clientes. Estabelecem normas para tempos de resposta e de resolução, criando um quadro de responsabilização e garantindo uma experiência coerente e de qualidade.",
|
||||
"LEARN_MORE": "Saiba mais sobre SLA",
|
||||
"LOADING": "Buscando SLAs",
|
||||
"PAYWALL": {
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"ENTERPRISE_PAYWALL": {
|
||||
"AVAILABLE_ON": "O recurso SLA está disponível apenas nos planos pagos.",
|
||||
"UPGRADE_PROMPT": "Atualize para um plano pago para acessar recursos avançados como logs de auditoria, capacidade do agente e muito mais.",
|
||||
"UPGRADE_PROMPT": "Atualize para um plano pago para acessar recursos avançados como registros de auditoria, capacidade do agente e muito mais.",
|
||||
"ASK_ADMIN": "Entre em contato com seu administrador para fazer a atualização."
|
||||
},
|
||||
"LIST": {
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Selectați agentul",
|
||||
"TEAM": "Selectați echipa"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Nimic"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Niciun agent găsit",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Выбрать Агента",
|
||||
"TEAM": "Выберите команду"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Ничего"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Операторы не найдены",
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "Контактная информация <strong>{primaryContactName}</strong> будет скопирована в <strong>{parentContactName}</strong>."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR_MESSAGE": "Что-то пошло не так. Пожалуйста, попробуйте позже."
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " Объединить контакты",
|
||||
@@ -563,7 +563,7 @@
|
||||
"GO_TO_CONVERSATION": "Просмотр",
|
||||
"SUCCESS_MESSAGE": "Сообщение успешно отправлено!",
|
||||
"ERROR_MESSAGE": "Произошла ошибка при создании диалога. Пожалуйста, повторите попытку позже.",
|
||||
"NO_INBOX_ALERT": "Нет доступных входящих для начала разговора с этим контактом.",
|
||||
"NO_INBOX_ALERT": "Нет доступных \"входящих\" для начала разговора с этим контактом.",
|
||||
"CONTACT_SELECTOR": {
|
||||
"LABEL": "Кому:",
|
||||
"TAG_INPUT_PLACEHOLDER": "Поиск контакта с именем, email или номером телефона",
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
},
|
||||
"PERMISSIONS": {
|
||||
"CONVERSATION_MANAGE": "Управление всеми диалогами",
|
||||
"CONVERSATION_UNASSIGNED_MANAGE": "Управление неназначенными беседами и теми, которые им назначены",
|
||||
"CONVERSATION_UNASSIGNED_MANAGE": "Управление неназначенными беседами и теми, которые назначены им",
|
||||
"CONVERSATION_PARTICIPATING_MANAGE": "Управление текущими беседами и теми, которые им назначены",
|
||||
"CONTACT_MANAGE": "Управление контактами",
|
||||
"REPORT_MANAGE": "Управление отчетами",
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
"CHANGE_PRIORITY": "Изменить приоритет",
|
||||
"CHANGE_TEAM": "Изменить команду",
|
||||
"SNOOZE_CONVERSATION": "Включить звук диалога",
|
||||
"ADD_LABEL": "Добавить метку в диалог",
|
||||
"ADD_LABEL": "Добавить метку в разговор",
|
||||
"REMOVE_LABEL": "Удалить метку из диалога",
|
||||
"SETTINGS": "Настройки",
|
||||
"AI_ASSIST": "Помощь ИИ",
|
||||
@@ -128,11 +128,11 @@
|
||||
"GO_TO_CONVERSATION_REPORTS": "Перейти к отчетам по диалогам",
|
||||
"GO_TO_AGENT_REPORTS": "Перейти к отчетам по сотрудникам",
|
||||
"GO_TO_LABEL_REPORTS": "Перейти к отчетам по меткам",
|
||||
"GO_TO_INBOX_REPORTS": "Перейти к отчётам по «Входящим»",
|
||||
"GO_TO_INBOX_REPORTS": "Перейти к отчётам по \"Входящим\"",
|
||||
"GO_TO_TEAM_REPORTS": "Перейти к отчетам по командам",
|
||||
"GO_TO_SETTINGS_AGENTS": "Перейти к настройкам сотрудников",
|
||||
"GO_TO_SETTINGS_TEAMS": "Перейти к настройкам команд",
|
||||
"GO_TO_SETTINGS_INBOXES": "Перейти к настройкам «Входящих»",
|
||||
"GO_TO_SETTINGS_INBOXES": "Перейти к настройкам \"Входящих\"",
|
||||
"GO_TO_SETTINGS_LABELS": "Перейти к настройкам меток",
|
||||
"GO_TO_SETTINGS_CANNED_RESPONSES": "Перейти к настройкам шаблонных ответов",
|
||||
"GO_TO_SETTINGS_APPLICATIONS": "Перейти в настройки приложения",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"INBOX_MGMT": {
|
||||
"HEADER": "Источники",
|
||||
"DESCRIPTION": "Канал — это способ коммуникации, который ваш клиент выбирает для связи с вами. Входящие — это место, где вы управляете диалогами для определенного канала. Он может включать диалоги из различных источников, таких как электронная почта, онлайн чат или социальные сети.",
|
||||
"LEARN_MORE": "Узнать больше о «Входящих»",
|
||||
"LEARN_MORE": "Узнать больше о \"Входящих\"",
|
||||
"RECONNECTION_REQUIRED": "Входящие сообщения отключены. Вы не будете получать новые сообщения пока не пройдете авторизацию повторно.",
|
||||
"CLICK_TO_RECONNECT": "Нажмите здесь для повторного подключения.",
|
||||
"LIST": {
|
||||
@@ -208,8 +208,8 @@
|
||||
}
|
||||
},
|
||||
"WHATSAPP": {
|
||||
"TITLE": "Канал WhatsApp",
|
||||
"DESC": "Начните поддерживать своих клиентов через WhatsApp.",
|
||||
"TITLE": "WhatsApp канал",
|
||||
"DESC": "Начните поддерживать ваших клиентов через WhatsApp.",
|
||||
"PROVIDERS": {
|
||||
"LABEL": "Поставщик API",
|
||||
"TWILIO": "Twilio",
|
||||
|
||||
@@ -302,8 +302,8 @@
|
||||
"ERROR": "Произошла ошибка при отвязке задачи, пожалуйста, попробуйте ещё раз"
|
||||
},
|
||||
"DELETE": {
|
||||
"TITLE": "Вы уверены, что хотите удалить интеграцию?",
|
||||
"MESSAGE": "Вы уверены, что хотите удалить интеграцию?",
|
||||
"TITLE": "Are you sure you want to delete the integration?",
|
||||
"MESSAGE": "Are you sure you want to delete the integration?",
|
||||
"CONFIRM": "Да, удалить",
|
||||
"CANCEL": "Отменить"
|
||||
}
|
||||
@@ -317,18 +317,18 @@
|
||||
"YOU": "Вы",
|
||||
"USE": "Использовать это",
|
||||
"RESET": "Сброс",
|
||||
"SELECT_ASSISTANT": "Выбрать ассистента"
|
||||
"SELECT_ASSISTANT": "Select Assistant"
|
||||
},
|
||||
"PAYWALL": {
|
||||
"TITLE": "Обновите тарифный план, чтобы использовать Captain AI",
|
||||
"AVAILABLE_ON": "Капитан недоступен на бесплатном тарифном плане.",
|
||||
"UPGRADE_PROMPT": "Обновите тарифный план, чтобы получить доступ к нашим ассистентам, copilot и другим функциям.",
|
||||
"UPGRADE_PROMPT": "Обновите тарифный план, чтобы получить доступ к помощникам, Captain AI и другому.",
|
||||
"UPGRADE_NOW": "Обновить сейчас",
|
||||
"CANCEL_ANYTIME": "Вы можете изменить или отменить ваш тарифный план в любое время"
|
||||
},
|
||||
"ENTERPRISE_PAYWALL": {
|
||||
"AVAILABLE_ON": "Функция Captain AI доступна только в платном плане.",
|
||||
"UPGRADE_PROMPT": "Обновите тарифный план, чтобы получить доступ к нашим ассистентам, copilot и другим функциям.",
|
||||
"UPGRADE_PROMPT": "Обновите тарифный план, чтобы получить доступ к помощникам, Captain AI и другому.",
|
||||
"ASK_ADMIN": "Пожалуйста, обратитесь к вашему администратору для обновления."
|
||||
},
|
||||
"BANNER": {
|
||||
@@ -341,35 +341,35 @@
|
||||
"EDIT": "Обновить"
|
||||
},
|
||||
"ASSISTANTS": {
|
||||
"HEADER": "Ассистенты",
|
||||
"ADD_NEW": "Создать нового ассистента",
|
||||
"HEADER": "Помощники",
|
||||
"ADD_NEW": "Создать нового помощника",
|
||||
"DELETE": {
|
||||
"TITLE": "Вы уверены, что хотите удалить ассистента?",
|
||||
"DESCRIPTION": "Это действие необратимо. Удаление этого ассистента удалит его из всех подключенных источников и навсегда удалит все сгенерированные знания.",
|
||||
"TITLE": "Вы уверены, что хотите удалить помощника?",
|
||||
"DESCRIPTION": "Это действие необратимо. Удаление этого помощника удалит его из всех подключенных источников и навсегда удалит все сгенерированные знания.",
|
||||
"CONFIRM": "Да, удалить",
|
||||
"SUCCESS_MESSAGE": "Ассистент успешно удален",
|
||||
"ERROR_MESSAGE": "При удалении ассистента произошла ошибка. Пожалуйста, попробуйте еще раз."
|
||||
"SUCCESS_MESSAGE": "Помощник успешно удален",
|
||||
"ERROR_MESSAGE": "При удалении помощника произошла ошибка. Пожалуйста, попробуйте еще раз."
|
||||
},
|
||||
"FORM_DESCRIPTION": "Заполните приведенные ниже сведения, чтобы назвать своего ассистента, описать его цель и указать поддерживаемый продукт.",
|
||||
"FORM_DESCRIPTION": "Заполните приведенные ниже сведения, чтобы назвать своего помощника, описать его цель и указать поддерживаемый продукт.",
|
||||
"CREATE": {
|
||||
"TITLE": "Создать ассистента",
|
||||
"SUCCESS_MESSAGE": "Ассистент успешно создан",
|
||||
"ERROR_MESSAGE": "При создании ассистента произошла ошибка, пожалуйста, попробуйте еще раз."
|
||||
"TITLE": "Создать помощника",
|
||||
"SUCCESS_MESSAGE": "Помощник успешно создан",
|
||||
"ERROR_MESSAGE": "При создании помощника произошла ошибка, пожалуйста, попробуйте еще раз."
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Имя ассистента",
|
||||
"PLACEHOLDER": "Введите имя ассистента",
|
||||
"ERROR": "Пожалуйста, укажите имя ассистента"
|
||||
"LABEL": "Имя помощника",
|
||||
"PLACEHOLDER": "Введите имя помощника",
|
||||
"ERROR": "Пожалуйста, укажите имя помощника"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Описание ассистента",
|
||||
"PLACEHOLDER": "Опишите, как и где будет использоваться этот ассистент",
|
||||
"LABEL": "Описание помощника",
|
||||
"PLACEHOLDER": "Опишите, как и где будет использоваться этот помощник",
|
||||
"ERROR": "Необходимо описание"
|
||||
},
|
||||
"PRODUCT_NAME": {
|
||||
"LABEL": "Название продукта",
|
||||
"PLACEHOLDER": "Введите название продукта, для которого предназначен этот ассистент",
|
||||
"PLACEHOLDER": "Введите название продукта, для которого предназначен этот помощник",
|
||||
"ERROR": "Требуется название продукта"
|
||||
},
|
||||
"FEATURES": {
|
||||
@@ -379,18 +379,18 @@
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"TITLE": "Обновить ассистента",
|
||||
"SUCCESS_MESSAGE": "Ассистент успешно обновлен",
|
||||
"ERROR_MESSAGE": "При обновлении ассистента произошла ошибка, пожалуйста, попробуйте еще раз."
|
||||
"TITLE": "Обновить помощника",
|
||||
"SUCCESS_MESSAGE": "Помощник успешно обновлен",
|
||||
"ERROR_MESSAGE": "При обновлении помощника произошла ошибка, пожалуйста, попробуйте еще раз."
|
||||
},
|
||||
"OPTIONS": {
|
||||
"EDIT_ASSISTANT": "Редактировать ассистента",
|
||||
"DELETE_ASSISTANT": "Удалить ассистента",
|
||||
"EDIT_ASSISTANT": "Редактировать помощника",
|
||||
"DELETE_ASSISTANT": "Удалить помощника",
|
||||
"VIEW_CONNECTED_INBOXES": "Просмотр подключенных источников"
|
||||
},
|
||||
"EMPTY_STATE": {
|
||||
"TITLE": "Нет доступных ассистентов",
|
||||
"SUBTITLE": "Создайте ассистента, чтобы дать быстрые и точные ответы пользователям. Он может учиться на ваших статьях из центра поддержки и прошлых диалогах."
|
||||
"TITLE": "Нет доступных помощников",
|
||||
"SUBTITLE": "Создайте помощника, чтобы дать быстрые и точные ответы пользователям. Он может учиться на ваших статьях из центра поддержки и прошлых диалогах."
|
||||
}
|
||||
},
|
||||
"DOCUMENTS": {
|
||||
@@ -413,9 +413,9 @@
|
||||
"ERROR": "Пожалуйста, укажите корректный URL для документа"
|
||||
},
|
||||
"ASSISTANT": {
|
||||
"LABEL": "Ассистент",
|
||||
"PLACEHOLDER": "Выберите ассистента",
|
||||
"ERROR": "Необходимо заполнить поле ассистента"
|
||||
"LABEL": "Помощник",
|
||||
"PLACEHOLDER": "Выберите помощника",
|
||||
"ERROR": "Необходимо заполнить поле помощника"
|
||||
}
|
||||
},
|
||||
"DELETE": {
|
||||
@@ -440,19 +440,19 @@
|
||||
"DOCUMENTABLE": {
|
||||
"CONVERSATION": "Диалог #{id}"
|
||||
},
|
||||
"SELECTED": "Выбрано {count}",
|
||||
"BULK_APPROVE_BUTTON": "Одобрить",
|
||||
"SELECTED": "{count} selected",
|
||||
"BULK_APPROVE_BUTTON": "Approve",
|
||||
"BULK_DELETE_BUTTON": "Удалить",
|
||||
"BULK_APPROVE": {
|
||||
"SUCCESS_MESSAGE": "FAQ успешно одобрены",
|
||||
"ERROR_MESSAGE": "Произошла ошибка при одобрении FAQ, пожалуйста, попробуйте ещё раз."
|
||||
"SUCCESS_MESSAGE": "FAQs approved successfully",
|
||||
"ERROR_MESSAGE": "There was an error approving the FAQs, please try again."
|
||||
},
|
||||
"BULK_DELETE": {
|
||||
"TITLE": "Удалить FAQ?",
|
||||
"DESCRIPTION": "Вы уверены, что хотите удалить выбранные FAQ? Это действие невозможно отменить.",
|
||||
"CONFIRM": "Да, удалить всё",
|
||||
"SUCCESS_MESSAGE": "FAQ успешно удалены",
|
||||
"ERROR_MESSAGE": "Произошла ошибка при удалении FAQ, пожалуйста, попробуйте ещё раз."
|
||||
"TITLE": "Delete FAQs?",
|
||||
"DESCRIPTION": "Are you sure you want to delete the selected FAQs? This action cannot be undone.",
|
||||
"CONFIRM": "Yes, delete all",
|
||||
"SUCCESS_MESSAGE": "FAQs deleted successfully",
|
||||
"ERROR_MESSAGE": "There was an error deleting the FAQs, please try again."
|
||||
},
|
||||
"DELETE": {
|
||||
"TITLE": "Вы действительно хотите удалить FAQ?",
|
||||
@@ -462,7 +462,7 @@
|
||||
"ERROR_MESSAGE": "Произошла ошибка при удалении FAQ, попробуйте еще раз."
|
||||
},
|
||||
"FILTER": {
|
||||
"ASSISTANT": "Ассистент: {selected}",
|
||||
"ASSISTANT": "Помощник: {selected}",
|
||||
"STATUS": "Статус: {selected}",
|
||||
"ALL_ASSISTANTS": "Все"
|
||||
},
|
||||
@@ -472,7 +472,7 @@
|
||||
"APPROVED": "Одобрено",
|
||||
"ALL": "Все"
|
||||
},
|
||||
"FORM_DESCRIPTION": "Добавьте вопрос и соответствующий ему ответ в базу знаний и выберите ассистента, с которым он должен связаться.",
|
||||
"FORM_DESCRIPTION": "Добавьте вопрос и соответствующий ему ответ в базу знаний и выберите помощника, с которым он должен связаться.",
|
||||
"CREATE": {
|
||||
"TITLE": "Добавить FAQ",
|
||||
"SUCCESS_MESSAGE": "Ответ успешно добавлен.",
|
||||
@@ -487,59 +487,59 @@
|
||||
"ANSWER": {
|
||||
"LABEL": "Ответ",
|
||||
"PLACEHOLDER": "Введите ответ",
|
||||
"ERROR": "Пожалуйста, введите корректный ответ."
|
||||
"ERROR": "Please provide a valid answer."
|
||||
},
|
||||
"ASSISTANT": {
|
||||
"LABEL": "Ассистент",
|
||||
"PLACEHOLDER": "Выбрать ассистента",
|
||||
"ERROR": "Выбрать ассистента"
|
||||
"LABEL": "Помощник",
|
||||
"PLACEHOLDER": "Select an assistant",
|
||||
"ERROR": "Please select an assistant."
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"TITLE": "Обновить FAQ",
|
||||
"SUCCESS_MESSAGE": "FAQ успешно обновлён",
|
||||
"ERROR_MESSAGE": "Произошла ошибка при обновлении FAQ, пожалуйста, попробуйте ещё раз",
|
||||
"APPROVE_SUCCESS_MESSAGE": "FAQ был отмечен как одобренный"
|
||||
"TITLE": "Update the FAQ",
|
||||
"SUCCESS_MESSAGE": "The FAQ has been successfully updated",
|
||||
"ERROR_MESSAGE": "There was an error updating the FAQ, please try again",
|
||||
"APPROVE_SUCCESS_MESSAGE": "The FAQ was marked as approved"
|
||||
},
|
||||
"OPTIONS": {
|
||||
"APPROVE": "Отметить как одобренный",
|
||||
"EDIT_RESPONSE": "FAQ отмечен как одобренный",
|
||||
"DELETE_RESPONSE": "Удалить FAQ"
|
||||
"APPROVE": "Mark as approved",
|
||||
"EDIT_RESPONSE": "Edit FAQ",
|
||||
"DELETE_RESPONSE": "Delete FAQ"
|
||||
},
|
||||
"EMPTY_STATE": {
|
||||
"TITLE": "FAQ не найдены",
|
||||
"SUBTITLE": "FAQ помогают вашему ассистенту быстро и точно отвечать на вопросы клиентов. Их можно генерировать автоматически из вашего контента или добавлять вручную."
|
||||
"TITLE": "No FAQs Found",
|
||||
"SUBTITLE": "FAQs help your assistant provide quick and accurate answers to questions from your customers. They can be generated automatically from your content or can be added manually."
|
||||
}
|
||||
},
|
||||
"INBOXES": {
|
||||
"HEADER": "Подключённые источники входящих",
|
||||
"ADD_NEW": "Подключить новый источник входящих",
|
||||
"HEADER": "Connected Inboxes",
|
||||
"ADD_NEW": "Connect a new inbox",
|
||||
"OPTIONS": {
|
||||
"DISCONNECT": "Отключиться"
|
||||
},
|
||||
"DELETE": {
|
||||
"TITLE": "Вы уверены, что хотите отключить этот источник входящих?",
|
||||
"TITLE": "Are you sure to disconnect the inbox?",
|
||||
"DESCRIPTION": "",
|
||||
"CONFIRM": "Да, удалить",
|
||||
"SUCCESS_MESSAGE": "Источник входящих успешно отключён.",
|
||||
"ERROR_MESSAGE": "Произошла ошибка при отключении источника входящих, пожалуйста, попробуйте ещё раз."
|
||||
"SUCCESS_MESSAGE": "The inbox was successfully disconnected.",
|
||||
"ERROR_MESSAGE": "There was an error disconnecting the inbox, please try again."
|
||||
},
|
||||
"FORM_DESCRIPTION": "Выберите источник входящих для подключения к ассистенту.",
|
||||
"FORM_DESCRIPTION": "Choose an inbox to connect with the assistant.",
|
||||
"CREATE": {
|
||||
"TITLE": "Подключить источник входящих",
|
||||
"SUCCESS_MESSAGE": "Источник входящих успешно подключён.",
|
||||
"ERROR_MESSAGE": "Произошла ошибка при подключении источника входящих. Пожалуйста, попробуйте ещё раз."
|
||||
"TITLE": "Connect an Inbox",
|
||||
"SUCCESS_MESSAGE": "The inbox was successfully connected.",
|
||||
"ERROR_MESSAGE": "An error occurred while connecting the inbox. Please try again."
|
||||
},
|
||||
"FORM": {
|
||||
"INBOX": {
|
||||
"LABEL": "Электронная почта",
|
||||
"PLACEHOLDER": "Выберите источник входящих для развертывания ассистента.",
|
||||
"ERROR": "Необходимо выбрать источник входящих."
|
||||
"PLACEHOLDER": "Choose the inbox to deploy the assistant.",
|
||||
"ERROR": "An inbox selection is required."
|
||||
}
|
||||
},
|
||||
"EMPTY_STATE": {
|
||||
"TITLE": "Нет подключённых источников входящих",
|
||||
"SUBTITLE": "Подключение источника входящих позволяет ассистенту обрабатывать первые вопросы ваших клиентов до их передачи вам."
|
||||
"TITLE": "No Connected Inboxes",
|
||||
"SUBTITLE": "Connecting an inbox allows the assistant to handle initial questions from your customers before transferring them to you."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
},
|
||||
"AGENT_REPORTS": {
|
||||
"HEADER": "Обзор агентов",
|
||||
"DESCRIPTION": "Легко отслеживайте эффективность работы агентов с помощью ключевых метрик, таких как количество бесед, время ответа, время решения проблем и количество решённых случаев. Нажмите на имя агента, чтобы узнать подробности.",
|
||||
"DESCRIPTION": "Easily track agent performance with key metrics such as conversations, response times, resolution times, and resolved cases. Click an agent’s name to learn more.",
|
||||
"LOADING_CHART": "Загрузка данных графика...",
|
||||
"NO_ENOUGH_DATA": "Недостаточно данных для создания отчета, пожалуйста, повторите попытку позже.",
|
||||
"DOWNLOAD_AGENT_REPORTS": "Сказать отчёт по агентам",
|
||||
@@ -259,7 +259,7 @@
|
||||
},
|
||||
"INBOX_REPORTS": {
|
||||
"HEADER": "Обзор входящих",
|
||||
"DESCRIPTION": "Быстро просматривайте эффективность источника входящих с основными метриками — количеством бесед, временем ответа, временем решения проблем и количеством решённых случаев — всё в одном месте. Нажмите на имя источника для получения подробной информации.",
|
||||
"DESCRIPTION": "Quickly view your inbox performance with key metrics like conversations, response times, resolution times, and resolved cases—all in one place. Click an inbox name for more details.",
|
||||
"LOADING_CHART": "Загрузка данных графика...",
|
||||
"NO_ENOUGH_DATA": "Недостаточно данных для создания отчета, пожалуйста, повторите попытку позже.",
|
||||
"DOWNLOAD_INBOX_REPORTS": "Скачать отчет по входящим",
|
||||
@@ -327,7 +327,7 @@
|
||||
},
|
||||
"TEAM_REPORTS": {
|
||||
"HEADER": "Обзор команды",
|
||||
"DESCRIPTION": "Получите обзор работы вашей команды с основными метриками, такими как количество бесед, время ответа, время решения проблем и количество решённых случаев. Нажмите на имя команды для подробностей.",
|
||||
"DESCRIPTION": "Get a snapshot of your team’s performance with essential metrics, including conversations, response times, resolution times, and resolved cases. Click a team name for more details.",
|
||||
"LOADING_CHART": "Загрузка данных графика...",
|
||||
"NO_ENOUGH_DATA": "Недостаточно данных для создания отчета, пожалуйста, повторите попытку позже.",
|
||||
"DOWNLOAD_TEAM_REPORTS": "Скачать отчет по команде",
|
||||
@@ -546,9 +546,9 @@
|
||||
"INBOX": "Электронная почта",
|
||||
"AGENT": "Оператор",
|
||||
"TEAM": "Команда",
|
||||
"AVG_RESOLUTION_TIME": "Среднее время решения",
|
||||
"AVG_FIRST_RESPONSE_TIME": "Среднее время первого ответа",
|
||||
"AVG_REPLY_TIME": "Среднее время ожидания клиента",
|
||||
"AVG_RESOLUTION_TIME": "Avg. Resolution Time",
|
||||
"AVG_FIRST_RESPONSE_TIME": "Avg. First Response Time",
|
||||
"AVG_REPLY_TIME": "Avg. Customer Waiting Time",
|
||||
"RESOLUTION_COUNT": "Количество завершенных",
|
||||
"CONVERSATIONS": "Количество диалогов"
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
"CONVERSATIONS": "Диалоги",
|
||||
"MESSAGES": "Сообщения"
|
||||
},
|
||||
"VIEW_MORE": "Посмотреть больше",
|
||||
"LOAD_MORE": "Загрузить ещё",
|
||||
"VIEW_MORE": "View more",
|
||||
"LOAD_MORE": "Load more",
|
||||
"SEARCHING_DATA": "Идёт поиск",
|
||||
"LOADING_DATA": "Загрузка",
|
||||
"EMPTY_STATE": "Не найдено {item} для запроса '{query}'",
|
||||
|
||||
@@ -36,20 +36,20 @@
|
||||
}
|
||||
},
|
||||
"INTERFACE_SECTION": {
|
||||
"TITLE": "Интерфейс",
|
||||
"NOTE": "Настройте внешний вид и оформление вашей панели Chatwoot.",
|
||||
"TITLE": "Interface",
|
||||
"NOTE": "Customize the look and feel of your Chatwoot dashboard.",
|
||||
"FONT_SIZE": {
|
||||
"TITLE": "Размер шрифта",
|
||||
"NOTE": "Измените размер текста на всей панели в соответствии с вашими предпочтениями.",
|
||||
"UPDATE_SUCCESS": "Настройки шрифта успешно обновлены",
|
||||
"UPDATE_ERROR": "Произошла ошибка при обновлении настроек шрифта, пожалуйста, попробуйте ещё раз",
|
||||
"TITLE": "Font size",
|
||||
"NOTE": "Adjust the text size across the dashboard based on your preference.",
|
||||
"UPDATE_SUCCESS": "Your font settings have been updated successfully",
|
||||
"UPDATE_ERROR": "There is an error while updating the font settings, please try again",
|
||||
"OPTIONS": {
|
||||
"SMALLER": "Меньше",
|
||||
"SMALL": "Маленький",
|
||||
"SMALLER": "Smaller",
|
||||
"SMALL": "Small",
|
||||
"DEFAULT": "По умолчанию",
|
||||
"LARGE": "Большой",
|
||||
"LARGER": "Крупнее",
|
||||
"EXTRA_LARGE": "Очень большой"
|
||||
"LARGE": "Large",
|
||||
"LARGER": "Larger",
|
||||
"EXTRA_LARGE": "Extra Large"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -162,7 +162,7 @@
|
||||
"REQUEST_PUSH": "Включить push-уведомления",
|
||||
"SLA_MISSED_FIRST_RESPONSE": "Отправить push-уведомление, если диалог не соответствует SLA первого ответа",
|
||||
"SLA_MISSED_NEXT_RESPONSE": "Отправить push-уведомление, если диалог не успел получить следующий ответ SLA",
|
||||
"SLA_MISSED_RESOLUTION": "Отправить push-уведомление, если диалог не соответствует SLA"
|
||||
"SLA_MISSED_RESOLUTION": "Отправить push-уведомление, если диалог не соответствует уровню разрешения SLA"
|
||||
},
|
||||
"PROFILE_IMAGE": {
|
||||
"LABEL": "Изображение профиля"
|
||||
@@ -281,9 +281,9 @@
|
||||
"SETTINGS": "Настройки",
|
||||
"CONTACTS": "Контакты",
|
||||
"CAPTAIN": "Капитан",
|
||||
"CAPTAIN_ASSISTANTS": "Ассистенты",
|
||||
"CAPTAIN_ASSISTANTS": "Помощники",
|
||||
"CAPTAIN_DOCUMENTS": "Документы",
|
||||
"CAPTAIN_RESPONSES": "FAQ",
|
||||
"CAPTAIN_RESPONSES": "FAQs",
|
||||
"HOME": "Главная",
|
||||
"AGENTS": "Операторы",
|
||||
"AGENT_BOTS": "Боты",
|
||||
@@ -345,14 +345,14 @@
|
||||
},
|
||||
"BILLING_SETTINGS": {
|
||||
"TITLE": "Платёж",
|
||||
"DESCRIPTION": "Управляйте подпиской здесь, обновите тарифный план и получите больше возможностей для вашей команды.",
|
||||
"DESCRIPTION": "Manage your subscription here, upgrade your plan and get more for your team.",
|
||||
"CURRENT_PLAN": {
|
||||
"TITLE": "Текущий план",
|
||||
"PLAN_NOTE": "На данный момент вы подписаны на ** план{plan}** с **{quantity}** лицензиями",
|
||||
"SEAT_COUNT": "Количество мест",
|
||||
"RENEWS_ON": "Продление"
|
||||
"SEAT_COUNT": "Number of seats",
|
||||
"RENEWS_ON": "Renews on"
|
||||
},
|
||||
"VIEW_PRICING": "Посмотреть цены",
|
||||
"VIEW_PRICING": "View Pricing",
|
||||
"MANAGE_SUBSCRIPTION": {
|
||||
"TITLE": "Управление подпиской",
|
||||
"DESCRIPTION": "Просматривайте ваши предыдущие счета, редактируйте платежные реквизиты или отмените подписку.",
|
||||
@@ -360,11 +360,11 @@
|
||||
},
|
||||
"CAPTAIN": {
|
||||
"TITLE": "Капитан",
|
||||
"DESCRIPTION": "Управляйте использованием и кредитами для Captain AI.",
|
||||
"BUTTON_TXT": "Купить дополнительные кредиты",
|
||||
"DESCRIPTION": "Manage usage and credits for Captain AI.",
|
||||
"BUTTON_TXT": "Buy more credits",
|
||||
"DOCUMENTS": "Документы",
|
||||
"RESPONSES": "Ответы",
|
||||
"UPGRADE": "Captain недоступен в бесплатном тарифном плане, обновите его, чтобы получить доступ к ассистентам, copilot и другим функциям."
|
||||
"RESPONSES": "Responses",
|
||||
"UPGRADE": "Captain is not available on the free plan, upgrade now to get access to assistants, copilot and more."
|
||||
},
|
||||
"CHAT_WITH_US": {
|
||||
"TITLE": "Нужна помощь?",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Select agent",
|
||||
"TEAM": "Select team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "None"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "No agents found",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Vybrať agenta",
|
||||
"TEAM": "Vybrať tím"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Žiadne"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Žiadni agenti neboli nájdení",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Select agent",
|
||||
"TEAM": "Select team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "None"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "No agents found",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Select agent",
|
||||
"TEAM": "Select team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "None"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "No agents found",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Izaberite agenta",
|
||||
"TEAM": "Izaberite tim"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Niko"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Nema pronađenih agenata",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Välj agent",
|
||||
"TEAM": "Välj team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Inget"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Inga agenter hittades",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Select agent",
|
||||
"TEAM": "Select team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "None"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "No agents found",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "เลือกพนักงาน",
|
||||
"TEAM": "เลือกทีม"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "ไม่มี"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "ไม่พบพนักงาน",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Select agent",
|
||||
"TEAM": "Select team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "None"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "No agents found",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Temsilci seçin",
|
||||
"TEAM": "Takım seçin"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Hiç"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Kullanıcı bulunamadı",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Виберіть агента",
|
||||
"TEAM": "Виберіть команду"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Нiчого"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Агентів не знайдено",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "ایجنٹ منتخب کریں۔",
|
||||
"TEAM": "ٹیم منتخب کریں۔"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "کوئی نہیں۔"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "کوئی ایجنٹ نہیں ملا",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Select agent",
|
||||
"TEAM": "Select team"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "None"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "No agents found",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "Chọn thành viên",
|
||||
"TEAM": "Chọn nhóm"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "Không có"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "Không tìm thấy nhà cung cấp",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "选择客服代表",
|
||||
"TEAM": "选择团队"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "啥都没有"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "未找到客服代表",
|
||||
|
||||
@@ -105,9 +105,6 @@
|
||||
"AGENT": "選擇客服",
|
||||
"TEAM": "選擇團隊"
|
||||
},
|
||||
"LIST": {
|
||||
"NONE": "無"
|
||||
},
|
||||
"SEARCH": {
|
||||
"NO_RESULTS": {
|
||||
"AGENT": "查無客服",
|
||||
|
||||
@@ -11,12 +11,14 @@ import {
|
||||
ACCOUNT_EVENTS,
|
||||
CONVERSATION_EVENTS,
|
||||
} from '../../../helper/AnalyticsHelper/events';
|
||||
import TranslateModal from 'dashboard/components/widgets/conversation/bubble/TranslateModal.vue';
|
||||
import MenuItem from '../../../components/widgets/conversation/contextMenu/menuItem.vue';
|
||||
import { useTrack } from 'dashboard/composables';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AddCannedModal,
|
||||
TranslateModal,
|
||||
MenuItem,
|
||||
ContextMenu,
|
||||
},
|
||||
@@ -52,6 +54,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
isCannedResponseModalOpen: false,
|
||||
showTranslateModal: false,
|
||||
showDeleteModal: false,
|
||||
};
|
||||
},
|
||||
@@ -122,11 +125,15 @@ export default {
|
||||
});
|
||||
useTrack(CONVERSATION_EVENTS.TRANSLATE_A_MESSAGE);
|
||||
this.handleClose();
|
||||
this.showTranslateModal = true;
|
||||
},
|
||||
handleReplyTo() {
|
||||
this.$emit('replyTo', this.message);
|
||||
this.handleClose();
|
||||
},
|
||||
onCloseTranslateModal() {
|
||||
this.showTranslateModal = false;
|
||||
},
|
||||
openDeleteModal() {
|
||||
this.handleClose();
|
||||
this.showDeleteModal = true;
|
||||
@@ -163,6 +170,13 @@ export default {
|
||||
:on-close="hideCannedResponseModal"
|
||||
/>
|
||||
</woot-modal>
|
||||
<!-- Translate Content -->
|
||||
<TranslateModal
|
||||
v-if="showTranslateModal"
|
||||
:content="messageContent"
|
||||
:content-attributes="contentAttributes"
|
||||
@close="onCloseTranslateModal"
|
||||
/>
|
||||
<!-- Confirm Deletion -->
|
||||
<woot-delete-modal
|
||||
v-if="showDeleteModal"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user